1 Functions

source_from_github(repositoy = "DEG_functions",version = "0.2.53")
source_from_github(repositoy = "HMSC_functions",version = "0.1.14",script_name = "functions.R")
source_from_github(repositoy = "cNMF_functions",version = "0.3.9",script_name = "cnmf_function_Harmony.R")
source_from_github(repositoy = "sc_general_functions",version = "0.1.34",script_name = "functions.R")

toc_tabs_level =3

2 Data

acc1_cancer_cells = readRDS("./Data/acc1_cancer_cells_2500features_integrated_V5.RDS")

all_acc_cancer_cells = readRDS("./Data/acc_cancer_cells_V5_integrated_primary.RDS")
acc_all_cells = readRDS("./Data/acc_tpm_nCount_mito_no146_15k_with_ACC1_.RDS")
acc_cancerCells_noACC1 = subset(all_acc_cancer_cells,subset = patient.ident != "HMSC")

luminal_pathways = c("CHARAFE_BREAST_CANCER_LUMINAL_VS_BASAL_DN","CHARAFE_BREAST_CANCER_LUMINAL_VS_BASAL_UP","CHARAFE_BREAST_CANCER_LUMINAL_VS_MESENCHYMAL_DN","CHARAFE_BREAST_CANCER_LUMINAL_VS_MESENCHYMAL_UP","HUPER_BREAST_BASAL_VS_LUMINAL_DN","LIM_MAMMARY_LUMINAL_PROGENITOR_UP","SMID_BREAST_CANCER_LUMINAL_B_UP" )

# add luminal pathwaysx 
luminal_gs = msigdbr(species = "Homo sapiens") %>% as.data.frame() %>% dplyr::filter(gs_name %in% luminal_pathways)%>% dplyr::distinct(gs_name, gene_symbol) %>% as.data.frame()

3 HMSC vs ACC

3.1 UMAP

DimPlot(all_acc_cancer_cells,group.by = "patient.ident",label = T)

FeaturePlot(object = all_acc_cancer_cells,features = c("MYB"),pt.size = 2)

FeaturePlot(object = all_acc_cancer_cells,features = c("kaye_acc_score"),pt.size = 1)

pdf("./Figures/kaye_acc_score_AllCancerCells.pdf")
FeaturePlot(object = all_acc_cancer_cells,features = c("kaye_acc_score"),pt.size = 1)
dev.off()
null device 
          1 

3.2 enrichment analysis

enrichment_analysis(acc_deg,background = VariableFeatures(all_acc_cancer_cells),fdr_Cutoff = 0.01,ident.1 = "HMSC",ident.2 = "ACC",show_by = 1)

3.3 Cell cycle score


hallmark_name = "GO_MITOTIC_CELL_CYCLE"
genesets  =getGmt("./Data/h.all.v7.0.symbols.pluscc.gmt")


acc_cancerCells_noACC1 = ScaleData(object = acc_cancerCells_noACC1,features = VariableFeatures(acc_cancerCells_noACC1,assay = "integrated"))
geneIds= genesets[[hallmark_name]]@geneIds %>% intersect(VariableFeatures(acc_cancerCells_noACC1,assay = "integrated")) 
score <- apply(acc_cancerCells_noACC1@assays$integrated@scale.data[geneIds,],2,mean)
acc_cancerCells_noACC1=AddMetaData(acc_cancerCells_noACC1,score,hallmark_name)

acc1_cancer_cells = FindVariableFeatures(object = acc1_cancer_cells,nfeatures = 15000)
acc1_cancer_cells = ScaleData(object = acc1_cancer_cells,features = VariableFeatures(acc1_cancer_cells))
geneIds= genesets[[hallmark_name]]@geneIds %>% intersect(VariableFeatures(acc1_cancer_cells)) 
score <- apply(acc1_cancer_cells@assays$integrated@scale.data[geneIds,],2,mean)
acc1_cancer_cells=AddMetaData(acc1_cancer_cells,score,hallmark_name)
acc_cc_scores = FetchData(object = acc_cancerCells_noACC1,vars = "GO_MITOTIC_CELL_CYCLE")
hmsc_cc_scores = FetchData(object = acc1_cancer_cells,vars = "GO_MITOTIC_CELL_CYCLE")

distributions_plt = ggplot() +
  geom_density(aes(GO_MITOTIC_CELL_CYCLE, fill = "ACC"), alpha = .2, data = acc_cc_scores) +
  geom_density(aes(GO_MITOTIC_CELL_CYCLE, fill = "HMSC"), alpha = .2, data = hmsc_cc_scores) +
  scale_fill_manual(name = "Dataset", values = c(ACC = "red", HMSC = "green"))+ geom_vline(aes(xintercept=0.3),
            color="blue", linetype="dashed", size=1) +ggtitle("'GO_MITOTIC_CELL_CYCLE'  score distribution")

print_tab(plt = distributions_plt,title = "score distribution",subtitle_num = 3)

score distribution

NA

hmsc_cc_cells = (sum(acc1_cancer_cells@meta.data[[hallmark_name]]> 0.3) /ncol(acc1_cancer_cells)) %>% round(digits = 3)*100
acc_cc_cells = (sum(acc_cancerCells_noACC1@meta.data[[hallmark_name]]> 0.3)/ncol(acc_cancerCells_noACC1)) %>% round(digits = 3)*100
df = data.frame(Dataset = c("HMSC","ACC"), cycling_cells_percentage = c(hmsc_cc_cells,acc_cc_cells))
cycling_cells_plt = ggplot(data=df, aes(x=Dataset, y=cycling_cells_percentage)) +
  geom_text(aes(label=cycling_cells_percentage), vjust=0, color="black", size=3.5)+
  geom_bar(stat="identity")+ylab(" % cycling cells")+
  geom_bar(stat="identity", fill="steelblue")+
  theme_minimal() + ggtitle("Cycling cells count")

print_tab(plt = cycling_cells_plt,title = "# cycling cells",subtitle_num = 3)

# cycling cells

NA

pdf(file = "./Figures/CC_distributions.pdf")
distributions_plt
dev.off()
null device 
          1 
pdf(file = "./Figures/cycling_cells.pdf")
cycling_cells_plt
dev.off()
null device 
          1 
print_tab(plt = 
            FeaturePlot(all_acc_cancer_cells,features = c("MKI67","CDK1","MCM2","CDC20"))
          ,title = "CC genes",subtitle_num = 3)

CC genes

NA

3.4 Cycling cells filtering

#add score to all acc cancer cells
# geneIds= genesets[[hallmark_name]]@geneIds %>% intersect(VariableFeatures(all_acc_cancer_cells,assay = "integrated")) 
# score <- apply(all_acc_cancer_cells@assays$integrated@scale.data[geneIds,],2,mean)

#add score to all acc cancer cells
cc_all = c(acc_cancerCells_noACC1$GO_MITOTIC_CELL_CYCLE, acc1_cancer_cells$GO_MITOTIC_CELL_CYCLE) %>% as.data.frame()
all_acc_cancer_cells=AddMetaData(all_acc_cancer_cells,cc_all,hallmark_name)

#filter:
all_acc_cancer_cells_ccFiltered=all_acc_cancer_cells[,all_acc_cancer_cells@meta.data[[hallmark_name]]< 0.3]


min_threshold = min(all_acc_cancer_cells$GO_MITOTIC_CELL_CYCLE)
max_threshold = max(all_acc_cancer_cells$GO_MITOTIC_CELL_CYCLE)
library(viridis)

Loading required package: viridisLite

print_tab(plt = FeaturePlot(object = all_acc_cancer_cells,features = hallmark_name) + ggtitle("Before cc filtering") &
            scale_color_gradientn(colours = plasma(n = 10, direction = -1), limits = c(min_threshold, max_threshold))
          ,title = "Before CC filtering",subtitle_num = 3)

Before CC filtering

Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.

print_tab(plt = 
            FeaturePlot(object = all_acc_cancer_cells_ccFiltered,features = hallmark_name) + ggtitle("After cc filtering") &
            scale_color_gradientn(colours = plasma(n = 10, direction = -1), limits = c(min_threshold, max_threshold))
          ,title = "After CC filtering" ,subtitle_num = 3)

After CC filtering

Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.

NA

3.5 DEG

all_acc_cancer_cells_ccFiltered = SetIdent(all_acc_cancer_cells_ccFiltered, value ="patient.ident")
acc_deg <-
  FindMarkers(
    all_acc_cancer_cells_ccFiltered,
    ident.1 = "HMSC",
    features = VariableFeatures(all_acc_cancer_cells_ccFiltered),
    densify = T,
    verbose = T,
    slot = "data",
    mean.fxn = function(x) {
      return(log(rowMeans(x) + 1,base = 2)) # change func to calculate logFC in log space data (default to exponent data)
    },
    assay = "RNA"
  )

| | 0 % ~calculating
|+ | 1 % ~12s
|+ | 2 % ~12s
|++ | 3 % ~12s
|++ | 4 % ~12s
|+++ | 5 % ~12s
|+++ | 6 % ~11s
|++++ | 7 % ~11s
|++++ | 8 % ~11s
|+++++ | 9 % ~11s
|+++++ | 10% ~10s
|++++++ | 11% ~10s
|++++++ | 12% ~10s
|+++++++ | 13% ~10s
|+++++++ | 14% ~10s
|++++++++ | 15% ~10s
|++++++++ | 16% ~09s
|+++++++++ | 17% ~09s
|+++++++++ | 18% ~09s
|++++++++++ | 19% ~09s
|++++++++++ | 20% ~09s
|+++++++++++ | 21% ~09s
|+++++++++++ | 22% ~09s
|++++++++++++ | 23% ~09s
|++++++++++++ | 24% ~09s
|+++++++++++++ | 25% ~08s
|+++++++++++++ | 26% ~08s
|++++++++++++++ | 27% ~08s
|++++++++++++++ | 28% ~08s
|+++++++++++++++ | 29% ~08s
|+++++++++++++++ | 30% ~08s
|++++++++++++++++ | 31% ~08s
|++++++++++++++++ | 32% ~08s
|+++++++++++++++++ | 33% ~07s
|+++++++++++++++++ | 34% ~08s
|++++++++++++++++++ | 35% ~08s
|++++++++++++++++++ | 36% ~07s
|+++++++++++++++++++ | 37% ~07s
|+++++++++++++++++++ | 38% ~07s
|++++++++++++++++++++ | 39% ~07s
|++++++++++++++++++++ | 40% ~07s
|+++++++++++++++++++++ | 41% ~07s
|+++++++++++++++++++++ | 42% ~07s
|++++++++++++++++++++++ | 43% ~07s
|++++++++++++++++++++++ | 44% ~06s
|+++++++++++++++++++++++ | 45% ~06s
|+++++++++++++++++++++++ | 46% ~06s
|++++++++++++++++++++++++ | 47% ~06s
|++++++++++++++++++++++++ | 48% ~06s
|+++++++++++++++++++++++++ | 49% ~06s
|+++++++++++++++++++++++++ | 50% ~06s
|++++++++++++++++++++++++++ | 51% ~06s
|++++++++++++++++++++++++++ | 52% ~05s
|+++++++++++++++++++++++++++ | 53% ~05s
|+++++++++++++++++++++++++++ | 54% ~05s
|++++++++++++++++++++++++++++ | 55% ~05s
|++++++++++++++++++++++++++++ | 56% ~05s
|+++++++++++++++++++++++++++++ | 57% ~05s
|+++++++++++++++++++++++++++++ | 58% ~05s
|++++++++++++++++++++++++++++++ | 59% ~05s
|++++++++++++++++++++++++++++++ | 60% ~04s
|+++++++++++++++++++++++++++++++ | 61% ~04s
|+++++++++++++++++++++++++++++++ | 62% ~04s
|++++++++++++++++++++++++++++++++ | 63% ~04s
|++++++++++++++++++++++++++++++++ | 64% ~04s
|+++++++++++++++++++++++++++++++++ | 65% ~04s
|+++++++++++++++++++++++++++++++++ | 66% ~04s
|++++++++++++++++++++++++++++++++++ | 67% ~04s
|++++++++++++++++++++++++++++++++++ | 68% ~04s
|+++++++++++++++++++++++++++++++++++ | 69% ~03s
|+++++++++++++++++++++++++++++++++++ | 70% ~03s
|++++++++++++++++++++++++++++++++++++ | 71% ~03s
|++++++++++++++++++++++++++++++++++++ | 72% ~03s
|+++++++++++++++++++++++++++++++++++++ | 73% ~03s
|+++++++++++++++++++++++++++++++++++++ | 74% ~03s
|++++++++++++++++++++++++++++++++++++++ | 75% ~03s
|++++++++++++++++++++++++++++++++++++++ | 76% ~03s
|+++++++++++++++++++++++++++++++++++++++ | 77% ~03s
|+++++++++++++++++++++++++++++++++++++++ | 78% ~02s
|++++++++++++++++++++++++++++++++++++++++ | 79% ~02s
|++++++++++++++++++++++++++++++++++++++++ | 80% ~02s
|+++++++++++++++++++++++++++++++++++++++++ | 81% ~02s
|+++++++++++++++++++++++++++++++++++++++++ | 82% ~02s
|++++++++++++++++++++++++++++++++++++++++++ | 83% ~02s
|++++++++++++++++++++++++++++++++++++++++++ | 84% ~02s
|+++++++++++++++++++++++++++++++++++++++++++ | 85% ~02s
|+++++++++++++++++++++++++++++++++++++++++++ | 86% ~02s
|++++++++++++++++++++++++++++++++++++++++++++ | 87% ~01s
|++++++++++++++++++++++++++++++++++++++++++++ | 88% ~01s
|+++++++++++++++++++++++++++++++++++++++++++++ | 89% ~01s
|+++++++++++++++++++++++++++++++++++++++++++++ | 90% ~01s
|++++++++++++++++++++++++++++++++++++++++++++++ | 91% ~01s
|++++++++++++++++++++++++++++++++++++++++++++++ | 92% ~01s
|+++++++++++++++++++++++++++++++++++++++++++++++ | 93% ~01s
|+++++++++++++++++++++++++++++++++++++++++++++++ | 94% ~01s
|++++++++++++++++++++++++++++++++++++++++++++++++ | 95% ~01s
|++++++++++++++++++++++++++++++++++++++++++++++++ | 96% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s
|+++++++++++++++++++++++++++++++++++++++++++++++++ | 98% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=12s

print_tab(plt = enrichment_analysis(acc_deg,background = VariableFeatures(all_acc_cancer_cells_ccFiltered),fdr_Cutoff = 0.01,ident.1 =
                                      "HMSC",ident.2 = "ACC",show_by = 1)
          ,title = "Enrichment after filtering",subtitle_num = 3)
###   Enrichment after filtering {.unnumbered }  

NA
library(hypeR)
genesets <- msigdb_download("Homo sapiens",category="H") %>% append( msigdb_download("Homo sapiens",category="C2",subcategory = "CP:KEGG"))
ranked_vec = acc_deg[,"avg_log2FC"]%>% setNames(rownames(acc_deg)) %>% na.omit() # make named vector

hyp_obj <-hypeR_fgsea(signature = ranked_vec,genesets = genesets,up_only = F)

plt = hyp_dots(hyp_obj,merge = F)
plt1 = plt$up+ aes(size=nes)+ggtitle("up in HMSC")
plt2 = plt$dn+ aes(size=abs(nes))+ggtitle("up in ACC")
plt3 = plt1+plt2
plt3

pdf(file = "./Figures/ACC_vs_HMSC_GSEA.pdf",width = 13,height = 6)
plt3
dev.off()
null device 
          1 
volcano_plot(de_genes = acc_deg,fdr_cutoff = 0.05,fc_cutoff = 2, ident1 = "HMSC",ident2 = "ACC",top_genes_text = 4)

all_acc_cancer_cells_ccFiltered = SetIdent(all_acc_cancer_cells_ccFiltered, value ="patient.ident")
acc_deg <-
  FindMarkers(
    all_acc_cancer_cells_ccFiltered,
    ident.1 = "HMSC",
    features = VariableFeatures(all_acc_cancer_cells_ccFiltered),
    densify = T,
    verbose = T,
    slot = "data",
    mean.fxn = function(x) {
      return(rowMeans(x) + 1) # change func to calculate logFC in log space data (default to exponent data)
    },
    assay = "RNA"
  )
volcano_plot(de_genes = acc_deg,fdr_cutoff = 0.05,fc_cutoff = 2, ident1 = "HMSC",ident2 = "ACC",top_genes_text = 4)+xlab("avg diff")

pdf("./Figures/volcano_plot_ACC_VS_HMSC.pdf")
volcano_plot(de_genes = acc_deg,fdr_cutoff = 0.05,fc_cutoff = 2, ident1 = "HMSC",ident2 = "ACC",top_genes_text = 4)
dev.off()
null device 
          1 
pdf("./Figures/Enrichment_analysis_ACC_VS_HMSC.pdf")
enrichment_analysis(acc_deg,background = VariableFeatures(all_acc_cancer_cells_ccFiltered),fdr_Cutoff = 0.01,ident.1 =
                                      "HMSC",ident.2 = "ACC",show_by = 1)
dev.off()
null device 
          1 
top_hmsc_genes = acc_deg %>% dplyr::filter(avg_log2FC > 0) %>%  slice_min(n = 10,order_by = p_val_adj) %>% rownames()
top_acc_genes = acc_deg %>% dplyr::filter(avg_log2FC < 0) %>%  slice_min(n = 10,order_by = p_val_adj) %>% rownames()
all_top_deg = c(top_hmsc_genes,top_acc_genes)

all_acc_cancer_cells_ccFiltered$cancer_type = all_acc_cancer_cells_ccFiltered$patient.ident %>% gsub(pattern = "ACC.*",replacement = "ACC")
cancer_type = FetchData(object = all_acc_cancer_cells_ccFiltered, vars = "cancer_type")
# col_list = list(circlize::colorRamp2(c(0, 1), c("white", "red"))); names(col_list) = colnames(all_metagenes)[i]
column_ha = HeatmapAnnotation(df = cancer_type)

data = FetchData(object = all_acc_cancer_cells_ccFiltered,vars = all_top_deg,slot = "scale.data") %>% t()

print(ComplexHeatmap::Heatmap(data,show_column_names = F,row_names_gp = grid::gpar(fontsize = 7),cluster_rows = F, ,name = "Z-score expression",cluster_columns = F,top_annotation = column_ha))

NA
NA

3.6 CNV plot

# create expression matrix of acc + normal cells + HMSC seurat integrated
# acc_all_cells_noAcc1 = subset(acc_all_cells, subset = patient.ident != "ACC1")
# acc_expr = acc_all_cells_noAcc1@assays$RNA@data %>% as.data.frame()
# hmsc_expr  = acc.combined@assays$integrated@data %>% as.data.frame()
# acc_expr = acc_expr [ rownames(hmsc_expr),]
# all_expr = cbind(acc_expr,hmsc_expr)
# 
# # create annotation 
# acc_annotation_integrated  = as.data.frame(acc_all_cells@meta.data[,"cell.type",drop = F])
# acc_annotation_integrated = acc_annotation_integrated[colnames(all_expr),,drop = F]
# acc_annotation_integrated = acc_annotation_integrated %>% rownames_to_column("orig.ident") 

# #write expression and annotation
# write.table(acc_annotation_integrated, "./Data/inferCNV/acc_annotation_integrated.txt", append = FALSE, 
#             sep = "\t", dec = ".",row.names = FALSE, col.names = F)
# 
# 
# write.table(all_expr, "./Data/inferCNV/all.4icnv_integrated.txt", append = FALSE, 
#             sep = "\t", dec = ".",row.names = T, col.names = T)
trace(infercnv::run,edit = T) # to skip normalization, change to skip_past = 4 (https://github.com/broadinstitute/infercnv/issues/346)
Tracing function "run" in package "infercnv"
[1] "run"

infercnv_obj = CreateInfercnvObject(raw_counts_matrix="./Data/inferCNV/all.4icnv_integrated.txt", 
                                    annotations_file="./Data/inferCNV/acc_annotation_integrated.txt",
                                    delim="\t",gene_order_file="./Data/inferCNV/gencode_v19_gene_pos.txt"
                                    ,ref_group_names=c("CAF", "Endothelial", "WBC")) #groups of normal cells

infercnv_obj_default = infercnv::run(infercnv_obj, cutoff=1, out_dir='./Data/inferCNV/infercnv_intergrated_output',
                                     cluster_by_groups=T, plot_steps=FALSE,
                                     denoise=TRUE, HMM=FALSE, no_prelim_plot=TRUE,
                                     png_res=300)
untrace(infercnv::run)
trace(infercnv:::get_group_color_palette ,edit = T) # change "Set3" to "Set1" for more distinguishable colors
plot_cnv(infercnv_obj_default, output_format = "png",  write_expr_matrix = FALSE,out_dir = "./Data/inferCNV/infercnv_intergrated_output",png_res    =800,obs_title = "Malignant cells",ref_title = "Normal cells",contig_cex = 2, title = "Copy number variation")
untrace(infercnv:::get_group_color_palette)
print_tab(plt = knitr::include_graphics("./Data/inferCNV/infercnv_intergrated_output/infercnv.png")
          ,title = "CNV plot",subtitle_num = 3)

CNV plot

NA

library(limma)
smoothed=apply(infercnv_obj_default@expr.data,2,tricubeMovingAverage, span=0.01)
cnsig=sqrt(apply((smoothed-1)^2,2,mean))

acc_all_cells <- AddMetaData(object = acc_all_cells, metadata = cnsig, col.name = "copynumber")
acc_all_cells = SetIdent(object = acc_all_cells,value = "cell.type")

print_tab(plt = FeaturePlot(acc_all_cells, "copynumber",pt.size = 1,label = T,repel = T)+
            scale_colour_gradientn(colours=c("white","lightblue","orange","red","darkred"))
          ,title = "CNV UMAP",subtitle_num = 3)

CNV UMAP

Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.

NA

4 HMSC analysis

4.1 UMAP

acc1_cancer_cells = FindClusters(object = acc1_cancer_cells,verbose = F,resolution = 0.5)
DimPlot(object = acc1_cancer_cells,pt.size = 2)

4.2 Scores

FeaturePlot(object = acc1_cancer_cells,features = c("MYB","JAG1"),pt.size = 2)+
DimPlot(object = acc1_cancer_cells,group.by  = c("hpv33_positive"),pt.size = 2)

4.3 DEG

SetIdent(object = acc1_cancer_cells,value = "seurat_clusters")

An object of class Seurat 80474 features across 134 samples within 2 assays Active assay: integrated (40237 features, 15000 variable features) 1 other assay present: RNA 2 dimensional reductions calculated: pca, umap

deg = FindAllMarkers(object = acc1_cancer_cells,features = VariableFeatures(acc1_cancer_cells),densify = T,verbose = F)
for (cluster in unique(deg$cluster)) {
  print_tab(plt = deg[deg$cluster == cluster,],title = "DEG" ,subtitle_num = toc_tabs_level)
}

DEG

DEG

NA

for (cluster in unique(deg$cluster)) {
  deg_of_cluster = deg[deg$cluster == cluster,] 
  #  print(deg_of_cluster %in% original_myo_genes %>% which())
  # print(deg_of_cluster %in% original_lum_genes %>% which())
  print_tab(plt = 
              enrichment_analysis(deg_of_cluster,background =VariableFeatures(acc1_cancer_cells),fdr_Cutoff = 0.01,ident.1 =
                                   paste("Cluster",cluster),ident.2 =  paste("Cluster",cluster),show_by = 1)
            ,title = cluster,subtitle_num = toc_tabs_level)
}

0

1

NA

4.4 NMF

reticulate::repl_python()
from cnmf import cNMF
import pickle
nfeatures = "2K"
f = open('./Data/cNMF/HMSC_cNMF_harmony_2Kvargenes/cnmf_obj.pckl', 'rb')
cnmf_obj = pickle.load(f)
f.close()
quit
knitr::include_graphics("./Data/cNMF/HMSC_cNMF_harmony_2Kvargenes/HMSC_cNMF_harmony_2Kvargenes.k_selection.png")

reticulate::repl_python()
selected_k = 3
density_threshold = 0.1
cnmf_obj.consensus(k=selected_k, density_threshold=density_threshold,show_clustering=True)
usage_norm, gep_scores, gep_tpm, topgenes = cnmf_obj.load_results(K=selected_k, density_threshold=density_threshold)
quit
gep_scores = py$gep_scores
gep_tpm = py$gep_tpm
all_metagenes= py$usage_norm

4.5 Harmony results

# Make metagene names
for (i in 1:ncol(all_metagenes)) {
  colnames(all_metagenes)[i] = "metagene." %>% paste0(i)
}

#add each metagene to metadata
for (i in 1:ncol(all_metagenes)) {
  metage_metadata = all_metagenes %>% select(i)
  acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = metage_metadata)
}

Note: Using an external vector in selections is ambiguous. ℹ Use all_of(i) instead of i to silence this message. ℹ See https://tidyselect.r-lib.org/reference/faq-external-vector.html. This message is displayed once per session.

print_tab(plt = 
            FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes),combine = T),
          title = "metagenes expression",subtitle_num = toc_tabs_level)

metagenes expression

NA

4.6 Enrichment analysis by top 200 genes of each program


canonical_pathways = msigdbr(species = "Homo sapiens", category = "C2") %>% dplyr::filter(gs_subcat != "CGP") %>%  dplyr::distinct(gs_name, gene_symbol)

plt_list = list()
for (i in 1:ncol(gep_scores)) {
  top_genes = gep_scores  %>%  arrange(desc(gep_scores[i])) #sort by score a
  top = head(rownames(top_genes),200) #take top top_genes_num
  res = genes_vec_enrichment(genes = top,background = rownames(gep_scores),homer = T,title = 
                    i,silent = T,return_all = T,custom_pathways = canonical_pathways)
   
  plt_list[[i]] = res$plt
}
gridExtra::grid.arrange(grobs = plt_list)

for (i in 1:ncol(gep_scores)) {
  ranked_vec = gep_scores %>% pull(i) %>%  setNames(rownames(gep_scores))
  hyp_obj <-hypeR_fgsea(signature = ranked_vec,genesets = genesets,up_only = T)

  plt = hyp_dots(hyp_obj,merge = F)+ aes(size=abs(nes))
  print(plt)
}

library(ComplexHeatmap)
acc1_cancer_cells = SetIdent(object = acc1_cancer_cells,value = "seurat_clusters")
for (i in 1:ncol(gep_scores)) {
  top_genes = gep_scores  %>%  arrange(desc(gep_scores[i])) #sort by score a
  top = head(rownames(top_genes),50) #take top top_genes_num
  data = FetchData(object = acc1_cancer_cells,vars = top)%>% scale() %>% t() 
  metagene_data = FetchData(object = acc1_cancer_cells,vars = colnames(all_metagenes)[i])
  col_list = list(circlize::colorRamp2(c(0, 1), c("white", "red"))); names(col_list) = colnames(all_metagenes)[i]
  column_ha = HeatmapAnnotation(df = metagene_data,col = col_list)
  print(ComplexHeatmap::Heatmap(data,show_column_names = F,row_names_gp = grid::gpar(fontsize = 7),cluster_rows = F, top_annotation = 
                                  column_ha,name = "Z-score expression"))
    
  pdf(paste0("./Figures/NMF_top_genes_program",i,".pdf"))
  print(ComplexHeatmap::Heatmap(data,show_column_names = F,row_names_gp = grid::gpar(fontsize = 7),cluster_rows = F, top_annotation = 
                                  column_ha,name = "Z-score expression"))
  dev.off()
}

4.7 Lum Myo score

original_myo_genes = c( "TP63", "TP73", "CAV1", "CDH3", "KRT5", "KRT14", "ACTA2", "TAGLN", "MYLK", "DKK3")
original_lum_genes = c("KIT", "EHF", "ELF5", "KRT7", "CLDN3", "CLDN4", "CD24", "LGALS3", "LCN2", "SLPI" )
FeaturePlot(acc1_cancer_cells,features = original_myo_genes)

FeaturePlot(acc1_cancer_cells,features = original_lum_genes)

acc_cancerCells_noACC1 = SetIdent(acc_cancerCells_noACC1,value = "patient.ident")
calculate_score(dataset = acc_cancerCells_noACC1,myo_genes = original_myo_genes,lum_genes = original_lum_genes)
correlation of lum score and myo score: -0.51
correlation of lum score and original lum score: 1
correlation of myo score and original myo score: 1

4.8 Original score of ACC1

calculate_score(dataset = acc1_cancer_cells,myo_genes = original_myo_genes,lum_genes = original_lum_genes,lum_threshold = 0,myo_threshold = 0)
correlation of lum score and myo score: -0.08
correlation of lum score and original lum score: 1
correlation of myo score and original myo score: 1

data = FetchData(object = acc1_cancer_cells,vars = c(original_lum_genes))
ComplexHeatmap::Heatmap(matrix = cor(data),name = "pearson")

4.8.1 Myo genes

myo_protein_markers = c("CNN1", "TP63","ACTA2")
top_myo  = top_correlated(dataset = acc1_cancer_cells, genes = myo_protein_markers,threshold = 0.35)
print("Number of genes = " %>% paste(length(top_myo)))
message("Names of genes:")
top_myo %>% head(30)
message("Genes that also apeared in the original score:")
base::intersect(top_myo,original_myo_genes) 
myo_enrich_res = genes_vec_enrichment(genes = top_myo,background = rownames(acc1_cancer_cells),homer = T,title = "myo top enrichment",custom_pathways = luminal_gs)
myo_enrich_res

4.8.2 Lum genes

lum_protein_markers = c("KIT")
top_lum  = top_correlated(dataset = acc1_cancer_cells, genes = lum_protein_markers,threshold = 0.30,n_vargenes = 5000)
print("Number of genes = " %>% paste(length(top_lum)))
message("Names of genes:")
top_lum %>% head(30)
message("Genes that also apeared in the original score:")
base::intersect(top_lum,original_lum_genes) 
lum_enrich_res = genes_vec_enrichment(genes = top_lum,background = rownames(acc1_cancer_cells),homer = T,title = "lum top enrichment",custom_pathways = luminal_gs)
lum_enrich_res
rownames(myo_enrich_res) = myo_enrich_res$pathway_name
myo_enriched_genes = myo_enrich_res[1,"geneID"] %>% strsplit(split = "/") %>% .[[1]] %>% c(.,myo_protein_markers) #add original markers
myoscore=FetchData(object =acc1_cancer_cells,vars =  myo_enriched_genes,slot = "data") %>% rowMeans()
acc1_cancer_cells=AddMetaData(acc1_cancer_cells,myoscore,"myo_score")


myoscore=FetchData(object =acc1_cancer_cells,vars =  top_myo,slot = "data") %>% rowMeans()
acc1_cancer_cells=AddMetaData(acc1_cancer_cells,myoscore,"myo_score")

4.9 HPV

4.9.1 HPV UMAP

HPV33_P3 = fread("./Data/HPV33_P3.txt",col.names = c("plate","reads")) %>% as.data.frame()
HPV33_P3.df = HPV33_P3 %>% mutate(
  plate = gsub(x =HPV33_P3$plate, replacement = "",pattern = "_.*$") 
  %>% gsub(pattern = "-P",replacement = ".P") 
  %>% gsub(pattern = "-",replacement = "_",)
  )
HPV33_P3.df = HPV33_P3.df %>% dplyr::filter(HPV33_P3.df$plate %in% colnames(acc1_cancer_cells))
rownames(HPV33_P3.df)  <- HPV33_P3.df$plate
HPV33_P3.df$plate = NULL


HPV33_P2 = fread("./Data/HPV33_P2.txt",col.names = c("plate","reads")) %>% as.data.frame()
HPV33_P2.df = HPV33_P2 %>% mutate(
  plate = gsub(x =HPV33_P2$plate, replacement = "",pattern = "_.*$") 
  %>% gsub(pattern = "plate2-",replacement = "plate2_",)
  %>% gsub(pattern = "-",replacement = "\\.",)
  )
HPV33_P2.df = HPV33_P2.df %>% dplyr::filter(HPV33_P2.df$plate %in% colnames(acc1_cancer_cells))
rownames(HPV33_P2.df)  <- HPV33_P2.df$plate
HPV33_P2.df$plate = NULL

HPV33 = rbind(HPV33_P3.df,HPV33_P2.df)
acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = HPV33,col.name = "HPV33.reads")
FeaturePlot(acc1_cancer_cells,features = "HPV33.reads",max.cutoff = 10)


data = FetchData(object = acc1_cancer_cells,vars = "HPV33.reads")

data = data %>% mutate("0 reads" = if_else(condition = HPV33.reads == 0,true = 1,false = 0))
data = data %>% mutate("1 reads" = if_else(condition = HPV33.reads == 1,true = 1,false = 0))
data = data %>% mutate("2 reads" = if_else(condition = HPV33.reads == 2,true = 1,false = 0))
data = data %>% mutate("3-23 reads" = if_else(condition = HPV33.reads >=3 &HPV33.reads  <24,true = 1,false = 0))
data = data %>% mutate("24+ reads" = if_else(condition = HPV33.reads >=24,true = 1,false = 0))
data = colSums(data[,2:ncol(data)]) %>% as.data.frame()
names(data)[1] = "count"
data = rownames_to_column(data,var = "bin")
data
ggplot(data=data, aes(x=factor(bin,levels = c("0 reads","1 reads","2 reads","3-23 reads","24+ reads")), y=count)) +
  geom_bar(stat="identity", fill="steelblue") + xlab("HPV Reads")+ theme_minimal()+
  geom_text(aes(label=count), vjust=-0.5, color="black", size=3.5)

hpv33_positive = HPV33 %>% dplyr::mutate(hpv33_positive = case_when(reads >= 10 ~ "positive",
                                                                    reads < 10 ~ "negative")
)



hpv33_positive$reads = NULL
acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = hpv33_positive)
DimPlot(object = acc1_cancer_cells,group.by  = c("hpv33_positive"),pt.size = 2)
Warning in grSoftVersion() :
  unable to load shared object '/usr/local/lib/R/modules//R_X11.so':
  libXt.so.6: cannot open shared object file: No such file or directory

FeaturePlot(object = acc1_cancer_cells,features = "MYB")

library(biomaRt)
ensembl = useEnsembl(biomart="ensembl", dataset="hsapiens_gene_ensembl")

4.9.2 DEG integrated wilcox

acc1_cancer_cells = FindVariableFeatures(acc1_cancer_cells,nfeatures = 25000,assay = "RNA.TPM")
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|

# library("biomaRt")
# mart <- useMart(biomart="ensembl", dataset="hsapiens_gene_ensembl")
# all_coding_genes <- getBM(attributes = c( "hgnc_symbol"), filters = c("biotype"), values = list(biotype="protein_coding"), mart = mart)
#    

features = VariableFeatures(acc1_cancer_cells) 
acc_deg <- FindMarkers(acc1_cancer_cells, ident.1 = "positive",ident.2 = "negative",features = features,densify = T,logfc.threshold = 0.25,min.pct = 0.15,    mean.fxn = function(x) {
      return(log(rowMeans(x) + 1, base = 2)) # change func to calculate logFC in log space data (default to exponent data)
    })
# enrichment_analysis(acc_deg,background = VariableFeatures(acc1_cancer_cells),fdr_Cutoff = 0.01,ident.1 = "HMSC",ident.2 = "ACC",show_by = 1)
acc_deg$fdr<-p.adjust(p = as.vector(acc_deg$p_val) ,method = "fdr")
# acc_deg[c("MYB","JAG1"),]
# acc_deg %>% head()
# genedesc <- getBM(attributes=c('external_gene_name','description'), filters = 'external_gene_name', values = acc_deg %>% rownames(), mart =ensembl)  
# 
# all_up_genes = merge(acc_deg,genedesc,by.x="row.names",by.y = "external_gene_name",all.x = T,sort =F)
# all_up_genes
# genes = all_up_genes %>% dplyr::filter(Row.names %in% c("MYB","JAG1")) %>% dplyr::filter(p_val<0.05)
# genes
acc_deg
acc_deg[c("MYB","JAG1"),]
NA

4.9.3 DEG LR latent vars plate

library("biomaRt")
# mart <- useMart(biomart="ensembl", dataset="hsapiens_gene_ensembl")
# all_coding_genes <- getBM(attributes = c( "hgnc_symbol"), filters = c("biotype"), values = list(biotype="protein_coding"), mart = mart)

features = VariableFeatures(acc1_cancer_cells)
features = acc1_cancer_cells@assays$RNA@data %>% rowMeans() %>% sort(decreasing = T) %>% head(3000) %>% names()
features  = intersect(features, VariableFeatures(acc1_cancer_cells) )
# features  = intersect(features, all_coding_genes[,1] )

acc_deg <-
  FindMarkers(
    acc1_cancer_cells,
    ident.1 = "positive",
    ident.2 = "negative",
    features = features,
    densify = T,
    assay = "RNA",
    test.use = "LR",
    latent.vars = "plate",
    logfc.threshold = 0.1,
    min.pct = 0.1,
    only.pos = F,
    mean.fxn = function(x) {
      return(log(rowMeans(x) + 1, base = 2)) # change func to calculate logFC in log space data (default to exponent data)
      # return(log(rowMeans(expm1(x)) + 1, base = 2))

    }
  )
acc_deg$fdr<-p.adjust(p = as.vector(acc_deg$p_val) ,method = "fdr" )
ranked_vec = acc_deg[,"avg_log2FC"]%>% setNames(rownames(acc_deg)) %>% na.omit() # make named vector

hyp_obj <-hypeR_fgsea(signature = ranked_vec,genesets = genesets,up_only = F)
hyp_dots(hyp_obj,merge = F)×–
acc_deg
acc_deg[c("MYB","JAG1"),]
NA

volcano plot log2(mean logTPM HPV+) - log2(mean logTPM HPV-)

volcano_plot(de_genes = acc_deg,fc_cutoff = 1.3, fdr_cutoff = 0.1,show_gene_names = c("MYB","JAG1"),ident1 = "HPV33 positive",ident2 = "HPV33 negative",top_genes_text = 5)


acc_deg2 = acc_deg %>% mutate(avg_log2FC = exp(avg_log2FC))
volcano_plot(de_genes = acc_deg2,fc_cutoff = 2**(1.3), fdr_cutoff = 0.1,show_gene_names = c("MYB","JAG1"),ident1 = "HPV33 positive",ident2 = "HPV33 negative",top_genes_text = 5)

volcano plot log2(mean logTPM HPV+) - log2(mean logTPM HPV-)


acc_deg <-
  FindMarkers(
    acc1_cancer_cells,
    ident.1 = "positive",
    ident.2 = "negative",
    features = features,
    densify = T,
    assay = "RNA",
    test.use = "LR",
    latent.vars = "plate",
    logfc.threshold = 0.35,
    min.pct = 0.1,
    mean.fxn = function(x) {
      return(rowMeans(x) + 1) # change func to calculate logFC in log space data (default to exponent data)
    }
  )
acc_deg$fdr<-p.adjust(p = as.vector(acc_deg$p_val) ,method = "fdr" )
acc_deg[c("MYB","JAG1"),]

volcano plot (mean logTPM HPV+) - (mean logTPM HPV-)

volcano_plot(de_genes = acc_deg,fc_cutoff = 1.3, fdr_cutoff = 0.1,show_gene_names = c("MYB","JAG1"),ident1 = "HPV33 positive",ident2 = "HPV33 negative",top_genes_text = 5)+xlab("avg diff")
Warning in de_genes$delabel[up_genes] <- `*vtmp*` :
  number of items to replace is not a multiple of replacement length

4.9.4 HPV vs genes

notch_genes = c("JAG1","JAG2","NOTCH3","NOTCH2","NOTCH1","DLL1","MYB","HES4","HEY1","HEY2","NRARP")
for (gene  in notch_genes) {
  myb_vs_hpv = FetchData(object = acc1_cancer_cells,vars = c("hpv33_positive",gene)) 
  myb_vs_hpv$hpv33_positive = paste("HPV33",myb_vs_hpv$hpv33_positiv)

  p = ggboxplot(myb_vs_hpv, x = "hpv33_positive", y = gene,
            palette = "jco",
            add = "jitter")+ stat_compare_means(method = "wilcox.test",comparisons = list(c("HPV33 positive","HPV33 negative")))+ stat_summary(fun.data = function(x) data.frame(y=max(x)*1.2, label = paste("Mean=",round(mean(x),digits = 2))), geom="text") +ylab("log2(gene)")+ggtitle(gene)
  print_tab(p,title = gene)
}
##   JAG1 {.unnumbered }  

 

##   JAG2 {.unnumbered }  

 

##   NOTCH3 {.unnumbered }  

 

##   NOTCH2 {.unnumbered }  

 

##   NOTCH1 {.unnumbered }  

 

##   DLL1 {.unnumbered }  

 

##   MYB {.unnumbered }  

 

##   HES4 {.unnumbered }  

 

##   HEY1 {.unnumbered }  

 

##   HEY2 {.unnumbered }  

 

##   NRARP {.unnumbered }  

NA
notch_targets = c("NOTCH3","HES4","HEY1","HEY2","NRARP") 
notch_ligand = c("JAG1","JAG2","DLL1")
notch_genes = list(notch_targets = notch_targets,notch_ligand = notch_ligand)
for (i  in 1:length(notch_genes)) {
  genes = notch_genes[[i]]
  name = names( notch_genes)[i]
  myb_vs_hpv = FetchData(object = acc1_cancer_cells,vars = c(genes)) %>% rowMeans()
  myb_vs_hpv = myb_vs_hpv %>% cbind(FetchData(object = acc1_cancer_cells,vars = c("hpv33_positive")))
  colnames(myb_vs_hpv)[1] = "gene_set"
  myb_vs_hpv$hpv33_positive = paste("HPV33",myb_vs_hpv$hpv33_positiv)

  p = ggboxplot(myb_vs_hpv, x = "hpv33_positive", y = "gene_set",
            palette = "jco",
            add = "jitter")+ stat_compare_means(method = "wilcox.test",comparisons = list(c("HPV33 positive","HPV33 negative")))+ stat_summary(fun.data = function(x) data.frame(y=max(x)*1.2, label = paste("Mean=",round(mean(x),digits = 2))), geom="text") +ylab("log2(gene)")+ggtitle(name)
 print(p)
}
  cor_data = FetchData(object = acc1_cancer_cells,vars = c("MYB","myo_score"))
ggplot(cor_data, aes(x=MYB, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()


  cor_data = FetchData(object = acc1_cancer_cells,vars = c("JAG1","myo_score"))
ggplot(cor_data, aes(x=JAG1, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()

  cor_data = FetchData(object = acc1_cancer_cells,vars = c("JAG2","myo_score"))
ggplot(cor_data, aes(x=JAG2, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()

  cor_data = FetchData(object = acc1_cancer_cells,vars = c("DLL1","myo_score"))
ggplot(cor_data, aes(x=DLL1, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()


  cor_data = FetchData(object = acc1_cancer_cells,vars = notch_targets) %>% rowMeans()
  cor_data = cor_data %>% cbind(FetchData(object = acc1_cancer_cells,vars = c("myo_score")))
  colnames(cor_data)[1] = "notch_targets"

  ggplot(cor_data, aes(x=notch_targets, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()
  
  
    cor_data = FetchData(object = acc1_cancer_cells,vars = notch_ligand) %>% rowMeans()
  cor_data = cor_data %>% cbind(FetchData(object = acc1_cancer_cells,vars = c("myo_score")))
  colnames(cor_data)[1] = "notch_ligand"

  ggplot(cor_data, aes(x=notch_ligand, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()
  
notch_score = FetchData(object = all_acc_cancer_cells,vars = notch_targets) %>% rowMeans()
all_acc_cancer_cells  = AddMetaData(object = all_acc_cancer_cells,metadata = notch_score,col.name = "notch_score")
FeaturePlot(object = all_acc_cancer_cells,features = "notch_score" )
myo_markers = c("TP63", "TP73", "KRT14", "CDH3")
score = FetchData(object = acc1_cancer_cells,vars = myo_markers) %>% rowMeans()
acc1_cancer_cells  = AddMetaData(object = acc1_cancer_cells,metadata = score,col.name = "myo_markers_score")
FeaturePlot(object = acc1_cancer_cells,features = "myo_markers_score",pt.size = 2 )


markers = c("CLDN3", "ANXA8", "EHF", "KIT")
score = FetchData(object = acc1_cancer_cells,vars = markers) %>% rowMeans()
acc1_cancer_cells  = AddMetaData(object = acc1_cancer_cells,metadata = score,col.name = "lum_markers_score")
FeaturePlot(object = acc1_cancer_cells,features = "lum_markers_score" ,pt.size = 2 )
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMgotLS0KCgoKIyBGdW5jdGlvbnMKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnNvdXJjZV9mcm9tX2dpdGh1YihyZXBvc2l0b3kgPSAiREVHX2Z1bmN0aW9ucyIsdmVyc2lvbiA9ICIwLjIuNTMiKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gIkhNU0NfZnVuY3Rpb25zIix2ZXJzaW9uID0gIjAuMS4xNCIsc2NyaXB0X25hbWUgPSAiZnVuY3Rpb25zLlIiKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gImNOTUZfZnVuY3Rpb25zIix2ZXJzaW9uID0gIjAuMy45IixzY3JpcHRfbmFtZSA9ICJjbm1mX2Z1bmN0aW9uX0hhcm1vbnkuUiIpCnNvdXJjZV9mcm9tX2dpdGh1YihyZXBvc2l0b3kgPSAic2NfZ2VuZXJhbF9mdW5jdGlvbnMiLHZlcnNpb24gPSAiMC4xLjM0IixzY3JpcHRfbmFtZSA9ICJmdW5jdGlvbnMuUiIpCgp0b2NfdGFic19sZXZlbCA9MwpgYGAKCiMgRGF0YQoKYGBge3J9CmFjYzFfY2FuY2VyX2NlbGxzID0gcmVhZFJEUygiLi9EYXRhL2FjYzFfY2FuY2VyX2NlbGxzXzI1MDBmZWF0dXJlc19pbnRlZ3JhdGVkX1Y1LlJEUyIpCgphbGxfYWNjX2NhbmNlcl9jZWxscyA9IHJlYWRSRFMoIi4vRGF0YS9hY2NfY2FuY2VyX2NlbGxzX1Y1X2ludGVncmF0ZWRfcHJpbWFyeS5SRFMiKQphbGxfYWNjX2NhbmNlcl9jZWxsc19sbiA9IHJlYWRSRFMoIi4vRGF0YS9hY2NfY2FuY2VyX2NlbGxzX1Y1X2ludGVncmF0ZWQuUkRTIikKCmFjY19hbGxfY2VsbHMgPSByZWFkUkRTKCIuL0RhdGEvYWNjX3RwbV9uQ291bnRfbWl0b19ubzE0Nl8xNWtfd2l0aF9BQ0MxXy5SRFMiKQphY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxID0gc3Vic2V0KGFsbF9hY2NfY2FuY2VyX2NlbGxzLHN1YnNldCA9IHBhdGllbnQuaWRlbnQgIT0gIkhNU0MiKQoKbHVtaW5hbF9wYXRod2F5cyA9IGMoIkNIQVJBRkVfQlJFQVNUX0NBTkNFUl9MVU1JTkFMX1ZTX0JBU0FMX0ROIiwiQ0hBUkFGRV9CUkVBU1RfQ0FOQ0VSX0xVTUlOQUxfVlNfQkFTQUxfVVAiLCJDSEFSQUZFX0JSRUFTVF9DQU5DRVJfTFVNSU5BTF9WU19NRVNFTkNIWU1BTF9ETiIsIkNIQVJBRkVfQlJFQVNUX0NBTkNFUl9MVU1JTkFMX1ZTX01FU0VOQ0hZTUFMX1VQIiwiSFVQRVJfQlJFQVNUX0JBU0FMX1ZTX0xVTUlOQUxfRE4iLCJMSU1fTUFNTUFSWV9MVU1JTkFMX1BST0dFTklUT1JfVVAiLCJTTUlEX0JSRUFTVF9DQU5DRVJfTFVNSU5BTF9CX1VQIiApCgojIGFkZCBsdW1pbmFsIHBhdGh3YXlzeCAKbHVtaW5hbF9ncyA9IG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBkcGx5cjo6ZmlsdGVyKGdzX25hbWUgJWluJSBsdW1pbmFsX3BhdGh3YXlzKSU+JSBkcGx5cjo6ZGlzdGluY3QoZ3NfbmFtZSwgZ2VuZV9zeW1ib2wpICU+JSBhcy5kYXRhLmZyYW1lKCkKYGBgCgoKCgojIEhNU0MgdnMgQUNDCgojIyBVTUFQCgpgYGB7cn0KRGltUGxvdChhbGxfYWNjX2NhbmNlcl9jZWxscyxncm91cC5ieSA9ICJwYXRpZW50LmlkZW50IixsYWJlbCA9IFQpCmBgYAoKYGBge3J9CkZlYXR1cmVQbG90KG9iamVjdCA9IGFsbF9hY2NfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gYygiTVlCIikscHQuc2l6ZSA9IDIpCmBgYApgYGB7cn0KRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWxsX2FjY19jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBjKCJrYXllX2FjY19zY29yZSIpLHB0LnNpemUgPSAxKQoKYGBgCmBgYHtyfQpwZGYoIi4vRmlndXJlcy9rYXllX2FjY19zY29yZV9BbGxDYW5jZXJDZWxscy5wZGYiKQpGZWF0dXJlUGxvdChvYmplY3QgPSBhbGxfYWNjX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IGMoImtheWVfYWNjX3Njb3JlIikscHQuc2l6ZSA9IDEpCmRldi5vZmYoKQpgYGAKCiMjIGVucmljaG1lbnQgYW5hbHlzaXMgCgpgYGB7ciBmaWcud2lkdGg9OCwgZWNobz1UUlVFLHJlc3VsdHM9J2hpZGUnLGZpZy5rZWVwPSdhbGwnfQphbGxfYWNjX2NhbmNlcl9jZWxscyA9IFNldElkZW50KGFsbF9hY2NfY2FuY2VyX2NlbGxzLCB2YWx1ZSA9InBhdGllbnQuaWRlbnQiKQphY2NfZGVnIDwtCiAgRmluZE1hcmtlcnMoCiAgICBhbGxfYWNjX2NhbmNlcl9jZWxscywKICAgIGlkZW50LjEgPSAiSE1TQyIsCiAgICBmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMoYWxsX2FjY19jYW5jZXJfY2VsbHMpLAogICAgZGVuc2lmeSA9IFQsCiAgICBhc3NheSA9ICJSTkEiLAogICAgbWVhbi5meG4gPSBmdW5jdGlvbih4KSB7CiAgICAgIHJldHVybihsb2cocm93TWVhbnMoeCkgKyAxLCBiYXNlID0gMikpICMgY2hhbmdlIGZ1biB0byBjYWxjdWxhdGUgbG9nRkMgaW4gbG9nIHNwYWNlIGRhdGEgKGRlZmF1bHQgdG8gZXhwb25lbnQgZGF0YSkKICAgIH0KICApCgpgYGAKCmBgYHtyfQplbnJpY2htZW50X2FuYWx5c2lzKGFjY19kZWcsYmFja2dyb3VuZCA9IFZhcmlhYmxlRmVhdHVyZXMoYWxsX2FjY19jYW5jZXJfY2VsbHMpLGZkcl9DdXRvZmYgPSAwLjAxLGlkZW50LjEgPSAiSE1TQyIsaWRlbnQuMiA9ICJBQ0MiLHNob3dfYnkgPSAxKQpgYGAKCiMjIENlbGwgY3ljbGUgc2NvcmUgIHsudGFic2V0fQpgYGB7cn0KCmhhbGxtYXJrX25hbWUgPSAiR09fTUlUT1RJQ19DRUxMX0NZQ0xFIgpnZW5lc2V0cyAgPWdldEdtdCgiLi9EYXRhL2guYWxsLnY3LjAuc3ltYm9scy5wbHVzY2MuZ210IikKCgphY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxID0gU2NhbGVEYXRhKG9iamVjdCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKGFjY19jYW5jZXJDZWxsc19ub0FDQzEsYXNzYXkgPSAiaW50ZWdyYXRlZCIpKQpnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dQGdlbmVJZHMgJT4lIGludGVyc2VjdChWYXJpYWJsZUZlYXR1cmVzKGFjY19jYW5jZXJDZWxsc19ub0FDQzEsYXNzYXkgPSAiaW50ZWdyYXRlZCIpKSAKc2NvcmUgPC0gYXBwbHkoYWNjX2NhbmNlckNlbGxzX25vQUNDMUBhc3NheXMkaW50ZWdyYXRlZEBzY2FsZS5kYXRhW2dlbmVJZHMsXSwyLG1lYW4pCmFjY19jYW5jZXJDZWxsc19ub0FDQzE9QWRkTWV0YURhdGEoYWNjX2NhbmNlckNlbGxzX25vQUNDMSxzY29yZSxoYWxsbWFya19uYW1lKQoKYWNjMV9jYW5jZXJfY2VsbHMgPSBGaW5kVmFyaWFibGVGZWF0dXJlcyhvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxuZmVhdHVyZXMgPSAxNTAwMCkKYWNjMV9jYW5jZXJfY2VsbHMgPSBTY2FsZURhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKGFjYzFfY2FuY2VyX2NlbGxzKSkKZ2VuZUlkcz0gZ2VuZXNldHNbW2hhbGxtYXJrX25hbWVdXUBnZW5lSWRzICU+JSBpbnRlcnNlY3QoVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscykpIApzY29yZSA8LSBhcHBseShhY2MxX2NhbmNlcl9jZWxsc0Bhc3NheXMkaW50ZWdyYXRlZEBzY2FsZS5kYXRhW2dlbmVJZHMsXSwyLG1lYW4pCmFjYzFfY2FuY2VyX2NlbGxzPUFkZE1ldGFEYXRhKGFjYzFfY2FuY2VyX2NlbGxzLHNjb3JlLGhhbGxtYXJrX25hbWUpCgoKCmBgYAoKCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CmFjY19jY19zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjX2NhbmNlckNlbGxzX25vQUNDMSx2YXJzID0gIkdPX01JVE9USUNfQ0VMTF9DWUNMRSIpCmhtc2NfY2Nfc2NvcmVzID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSAiR09fTUlUT1RJQ19DRUxMX0NZQ0xFIikKCmRpc3RyaWJ1dGlvbnNfcGx0ID0gZ2dwbG90KCkgKwogIGdlb21fZGVuc2l0eShhZXMoR09fTUlUT1RJQ19DRUxMX0NZQ0xFLCBmaWxsID0gIkFDQyIpLCBhbHBoYSA9IC4yLCBkYXRhID0gYWNjX2NjX3Njb3JlcykgKwogIGdlb21fZGVuc2l0eShhZXMoR09fTUlUT1RJQ19DRUxMX0NZQ0xFLCBmaWxsID0gIkhNU0MiKSwgYWxwaGEgPSAuMiwgZGF0YSA9IGhtc2NfY2Nfc2NvcmVzKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJEYXRhc2V0IiwgdmFsdWVzID0gYyhBQ0MgPSAicmVkIiwgSE1TQyA9ICJncmVlbiIpKSsgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD0wLjMpLAogICAgICAgICAgICBjb2xvcj0iYmx1ZSIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICtnZ3RpdGxlKCInR09fTUlUT1RJQ19DRUxMX0NZQ0xFJyAgc2NvcmUgZGlzdHJpYnV0aW9uIikKCnByaW50X3RhYihwbHQgPSBkaXN0cmlidXRpb25zX3BsdCx0aXRsZSA9ICJzY29yZSBkaXN0cmlidXRpb24iLHN1YnRpdGxlX251bSA9IDMpCgpgYGAKYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJ30KaG1zY19jY19jZWxscyA9IChzdW0oYWNjMV9jYW5jZXJfY2VsbHNAbWV0YS5kYXRhW1toYWxsbWFya19uYW1lXV0+IDAuMykgL25jb2woYWNjMV9jYW5jZXJfY2VsbHMpKSAlPiUgcm91bmQoZGlnaXRzID0gMykqMTAwCmFjY19jY19jZWxscyA9IChzdW0oYWNjX2NhbmNlckNlbGxzX25vQUNDMUBtZXRhLmRhdGFbW2hhbGxtYXJrX25hbWVdXT4gMC4zKS9uY29sKGFjY19jYW5jZXJDZWxsc19ub0FDQzEpKSAlPiUgcm91bmQoZGlnaXRzID0gMykqMTAwCmRmID0gZGF0YS5mcmFtZShEYXRhc2V0ID0gYygiSE1TQyIsIkFDQyIpLCBjeWNsaW5nX2NlbGxzX3BlcmNlbnRhZ2UgPSBjKGhtc2NfY2NfY2VsbHMsYWNjX2NjX2NlbGxzKSkKY3ljbGluZ19jZWxsc19wbHQgPSBnZ3Bsb3QoZGF0YT1kZiwgYWVzKHg9RGF0YXNldCwgeT1jeWNsaW5nX2NlbGxzX3BlcmNlbnRhZ2UpKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1jeWNsaW5nX2NlbGxzX3BlcmNlbnRhZ2UpLCB2anVzdD0wLCBjb2xvcj0iYmxhY2siLCBzaXplPTMuNSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSt5bGFiKCIgJSBjeWNsaW5nIGNlbGxzIikrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBmaWxsPSJzdGVlbGJsdWUiKSsKICB0aGVtZV9taW5pbWFsKCkgKyBnZ3RpdGxlKCJDeWNsaW5nIGNlbGxzIGNvdW50IikKCnByaW50X3RhYihwbHQgPSBjeWNsaW5nX2NlbGxzX3BsdCx0aXRsZSA9ICIjIGN5Y2xpbmcgY2VsbHMiLHN1YnRpdGxlX251bSA9IDMpCmBgYApgYGB7cn0KcGRmKGZpbGUgPSAiLi9GaWd1cmVzL0NDX2Rpc3RyaWJ1dGlvbnMucGRmIikKZGlzdHJpYnV0aW9uc19wbHQKZGV2Lm9mZigpCgpwZGYoZmlsZSA9ICIuL0ZpZ3VyZXMvY3ljbGluZ19jZWxscy5wZGYiKQpjeWNsaW5nX2NlbGxzX3BsdApkZXYub2ZmKCkKYGBgCgoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTAsIHJlc3VsdHM9J2FzaXMnfQpwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgIEZlYXR1cmVQbG90KGFsbF9hY2NfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gYygiTUtJNjciLCJDREsxIiwiTUNNMiIsIkNEQzIwIikpCiAgICAgICAgICAsdGl0bGUgPSAiQ0MgZ2VuZXMiLHN1YnRpdGxlX251bSA9IDMpCmBgYAoKIyMgQ3ljbGluZyBjZWxscyBmaWx0ZXJpbmcgey50YWJzZXR9CmBgYHtyIHdhcm5pbmc9RkFMU0V9CiNhZGQgc2NvcmUgdG8gYWxsIGFjYyBjYW5jZXIgY2VsbHMKIyBnZW5lSWRzPSBnZW5lc2V0c1tbaGFsbG1hcmtfbmFtZV1dQGdlbmVJZHMgJT4lIGludGVyc2VjdChWYXJpYWJsZUZlYXR1cmVzKGFsbF9hY2NfY2FuY2VyX2NlbGxzLGFzc2F5ID0gImludGVncmF0ZWQiKSkgCiMgc2NvcmUgPC0gYXBwbHkoYWxsX2FjY19jYW5jZXJfY2VsbHNAYXNzYXlzJGludGVncmF0ZWRAc2NhbGUuZGF0YVtnZW5lSWRzLF0sMixtZWFuKQoKI2FkZCBzY29yZSB0byBhbGwgYWNjIGNhbmNlciBjZWxscwpjY19hbGwgPSBjKGFjY19jYW5jZXJDZWxsc19ub0FDQzEkR09fTUlUT1RJQ19DRUxMX0NZQ0xFLCBhY2MxX2NhbmNlcl9jZWxscyRHT19NSVRPVElDX0NFTExfQ1lDTEUpICU+JSBhcy5kYXRhLmZyYW1lKCkKYWxsX2FjY19jYW5jZXJfY2VsbHM9QWRkTWV0YURhdGEoYWxsX2FjY19jYW5jZXJfY2VsbHMsY2NfYWxsLGhhbGxtYXJrX25hbWUpCgojZmlsdGVyOgphbGxfYWNjX2NhbmNlcl9jZWxsc19jY0ZpbHRlcmVkPWFsbF9hY2NfY2FuY2VyX2NlbGxzWyxhbGxfYWNjX2NhbmNlcl9jZWxsc0BtZXRhLmRhdGFbW2hhbGxtYXJrX25hbWVdXTwgMC4zXQoKCm1pbl90aHJlc2hvbGQgPSBtaW4oYWxsX2FjY19jYW5jZXJfY2VsbHMkR09fTUlUT1RJQ19DRUxMX0NZQ0xFKQptYXhfdGhyZXNob2xkID0gbWF4KGFsbF9hY2NfY2FuY2VyX2NlbGxzJEdPX01JVE9USUNfQ0VMTF9DWUNMRSkKYGBgCgoKYGBge3IsIHJlc3VsdHM9J2FzaXMnfQpsaWJyYXJ5KHZpcmlkaXMpCgpwcmludF90YWIocGx0ID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWxsX2FjY19jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBoYWxsbWFya19uYW1lKSArIGdndGl0bGUoIkJlZm9yZSBjYyBmaWx0ZXJpbmciKSAmCiAgICAgICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvdXJzID0gcGxhc21hKG4gPSAxMCwgZGlyZWN0aW9uID0gLTEpLCBsaW1pdHMgPSBjKG1pbl90aHJlc2hvbGQsIG1heF90aHJlc2hvbGQpKQogICAgICAgICAgLHRpdGxlID0gIkJlZm9yZSBDQyBmaWx0ZXJpbmciLHN1YnRpdGxlX251bSA9IDMpCgoKcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICBGZWF0dXJlUGxvdChvYmplY3QgPSBhbGxfYWNjX2NhbmNlcl9jZWxsc19jY0ZpbHRlcmVkLGZlYXR1cmVzID0gaGFsbG1hcmtfbmFtZSkgKyBnZ3RpdGxlKCJBZnRlciBjYyBmaWx0ZXJpbmciKSAmCiAgICAgICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvdXJzID0gcGxhc21hKG4gPSAxMCwgZGlyZWN0aW9uID0gLTEpLCBsaW1pdHMgPSBjKG1pbl90aHJlc2hvbGQsIG1heF90aHJlc2hvbGQpKQogICAgICAgICAgLHRpdGxlID0gIkFmdGVyIENDIGZpbHRlcmluZyIgLHN1YnRpdGxlX251bSA9IDMpCgpgYGAKIyMgREVHCgpgYGB7ciBmaWcud2lkdGg9OCwgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJyxmaWcua2VlcD0nYWxsJ30KYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCA9IFNldElkZW50KGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQsIHZhbHVlID0icGF0aWVudC5pZGVudCIpCmFjY19kZWcgPC0KICBGaW5kTWFya2VycygKICAgIGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQsCiAgICBpZGVudC4xID0gIkhNU0MiLAogICAgZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQpLAogICAgZGVuc2lmeSA9IFQsCiAgICB2ZXJib3NlID0gVCwKICAgIHNsb3QgPSAiZGF0YSIsCiAgICBtZWFuLmZ4biA9IGZ1bmN0aW9uKHgpIHsKICAgICAgcmV0dXJuKGxvZyhyb3dNZWFucyh4KSArIDEsYmFzZSA9IDIpKSAjIGNoYW5nZSBmdW5jIHRvIGNhbGN1bGF0ZSBsb2dGQyBpbiBsb2cgc3BhY2UgZGF0YSAoZGVmYXVsdCB0byBleHBvbmVudCBkYXRhKQogICAgfSwKICAgIGFzc2F5ID0gIlJOQSIKICApCmBgYAoKCmBgYHtyfQpwcmludF90YWIocGx0ID0gZW5yaWNobWVudF9hbmFseXNpcyhhY2NfZGVnLGJhY2tncm91bmQgPSBWYXJpYWJsZUZlYXR1cmVzKGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQpLGZkcl9DdXRvZmYgPSAwLjAxLGlkZW50LjEgPQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJITVNDIixpZGVudC4yID0gIkFDQyIsc2hvd19ieSA9IDEpCiAgICAgICAgICAsdGl0bGUgPSAiRW5yaWNobWVudCBhZnRlciBmaWx0ZXJpbmciLHN1YnRpdGxlX251bSA9IDMpCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEzLCByZXN1bHRzPSdhc2lzJ30KbGlicmFyeShoeXBlUikKZ2VuZXNldHMgPC0gbXNpZ2RiX2Rvd25sb2FkKCJIb21vIHNhcGllbnMiLGNhdGVnb3J5PSJIIikgJT4lIGFwcGVuZCggbXNpZ2RiX2Rvd25sb2FkKCJIb21vIHNhcGllbnMiLGNhdGVnb3J5PSJDMiIsc3ViY2F0ZWdvcnkgPSAiQ1A6S0VHRyIpKQpyYW5rZWRfdmVjID0gYWNjX2RlZ1ssImF2Z19sb2cyRkMiXSU+JSBzZXROYW1lcyhyb3duYW1lcyhhY2NfZGVnKSkgJT4lIG5hLm9taXQoKSAjIG1ha2UgbmFtZWQgdmVjdG9yCgpoeXBfb2JqIDwtaHlwZVJfZmdzZWEoc2lnbmF0dXJlID0gcmFua2VkX3ZlYyxnZW5lc2V0cyA9IGdlbmVzZXRzLHVwX29ubHkgPSBGKQoKcGx0ID0gaHlwX2RvdHMoaHlwX29iaixtZXJnZSA9IEYpCnBsdDEgPSBwbHQkdXArIGFlcyhzaXplPW5lcykrZ2d0aXRsZSgidXAgaW4gSE1TQyIpCnBsdDIgPSBwbHQkZG4rIGFlcyhzaXplPWFicyhuZXMpKStnZ3RpdGxlKCJ1cCBpbiBBQ0MiKQpwbHQzID0gcGx0MStwbHQyCnBsdDMKYGBgCgoKYGBge3J9CnBkZihmaWxlID0gIi4vRmlndXJlcy9BQ0NfdnNfSE1TQ19HU0VBLnBkZiIsd2lkdGggPSAxMyxoZWlnaHQgPSA2KQpwbHQzCmRldi5vZmYoKQpgYGAKCmBgYHtyfQp2b2xjYW5vX3Bsb3QoZGVfZ2VuZXMgPSBhY2NfZGVnLGZkcl9jdXRvZmYgPSAwLjA1LGZjX2N1dG9mZiA9IDIsIGlkZW50MSA9ICJITVNDIixpZGVudDIgPSAiQUNDIix0b3BfZ2VuZXNfdGV4dCA9IDQpCmBgYApgYGB7ciBmaWcud2lkdGg9OCwgZWNobz1UUlVFLCByZXN1bHRzPSdhc2lzJyxmaWcua2VlcD0nYWxsJ30KYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCA9IFNldElkZW50KGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQsIHZhbHVlID0icGF0aWVudC5pZGVudCIpCmFjY19kZWcgPC0KICBGaW5kTWFya2VycygKICAgIGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQsCiAgICBpZGVudC4xID0gIkhNU0MiLAogICAgZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQpLAogICAgZGVuc2lmeSA9IFQsCiAgICB2ZXJib3NlID0gVCwKICAgIHNsb3QgPSAiZGF0YSIsCiAgICBtZWFuLmZ4biA9IGZ1bmN0aW9uKHgpIHsKICAgICAgcmV0dXJuKHJvd01lYW5zKHgpICsgMSkgIyBjaGFuZ2UgZnVuYyB0byBjYWxjdWxhdGUgbG9nRkMgaW4gbG9nIHNwYWNlIGRhdGEgKGRlZmF1bHQgdG8gZXhwb25lbnQgZGF0YSkKICAgIH0sCiAgICBhc3NheSA9ICJSTkEiCiAgKQpgYGAKCgpgYGB7cn0Kdm9sY2Fub19wbG90KGRlX2dlbmVzID0gYWNjX2RlZyxmZHJfY3V0b2ZmID0gMC4wNSxmY19jdXRvZmYgPSAyLCBpZGVudDEgPSAiSE1TQyIsaWRlbnQyID0gIkFDQyIsdG9wX2dlbmVzX3RleHQgPSA0KSt4bGFiKCJhdmcgZGlmZiIpCmBgYAoKCgoKYGBge3J9CnBkZigiLi9GaWd1cmVzL3ZvbGNhbm9fcGxvdF9BQ0NfVlNfSE1TQy5wZGYiKQp2b2xjYW5vX3Bsb3QoZGVfZ2VuZXMgPSBhY2NfZGVnLGZkcl9jdXRvZmYgPSAwLjA1LGZjX2N1dG9mZiA9IDIsIGlkZW50MSA9ICJITVNDIixpZGVudDIgPSAiQUNDIix0b3BfZ2VuZXNfdGV4dCA9IDQpCmRldi5vZmYoKQoKcGRmKCIuL0ZpZ3VyZXMvRW5yaWNobWVudF9hbmFseXNpc19BQ0NfVlNfSE1TQy5wZGYiKQplbnJpY2htZW50X2FuYWx5c2lzKGFjY19kZWcsYmFja2dyb3VuZCA9IFZhcmlhYmxlRmVhdHVyZXMoYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCksZmRyX0N1dG9mZiA9IDAuMDEsaWRlbnQuMSA9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhNU0MiLGlkZW50LjIgPSAiQUNDIixzaG93X2J5ID0gMSkKZGV2Lm9mZigpCgpgYGAKCgoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9OH0KdG9wX2htc2NfZ2VuZXMgPSBhY2NfZGVnICU+JSBkcGx5cjo6ZmlsdGVyKGF2Z19sb2cyRkMgPiAwKSAlPiUgIHNsaWNlX21pbihuID0gMTAsb3JkZXJfYnkgPSBwX3ZhbF9hZGopICU+JSByb3duYW1lcygpCnRvcF9hY2NfZ2VuZXMgPSBhY2NfZGVnICU+JSBkcGx5cjo6ZmlsdGVyKGF2Z19sb2cyRkMgPCAwKSAlPiUgIHNsaWNlX21pbihuID0gMTAsb3JkZXJfYnkgPSBwX3ZhbF9hZGopICU+JSByb3duYW1lcygpCmFsbF90b3BfZGVnID0gYyh0b3BfaG1zY19nZW5lcyx0b3BfYWNjX2dlbmVzKQoKYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCRjYW5jZXJfdHlwZSA9IGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQkcGF0aWVudC5pZGVudCAlPiUgZ3N1YihwYXR0ZXJuID0gIkFDQy4qIixyZXBsYWNlbWVudCA9ICJBQ0MiKQpjYW5jZXJfdHlwZSA9IEZldGNoRGF0YShvYmplY3QgPSBhbGxfYWNjX2NhbmNlcl9jZWxsc19jY0ZpbHRlcmVkLCB2YXJzID0gImNhbmNlcl90eXBlIikKIyBjb2xfbGlzdCA9IGxpc3QoY2lyY2xpemU6OmNvbG9yUmFtcDIoYygwLCAxKSwgYygid2hpdGUiLCAicmVkIikpKTsgbmFtZXMoY29sX2xpc3QpID0gY29sbmFtZXMoYWxsX21ldGFnZW5lcylbaV0KY29sdW1uX2hhID0gSGVhdG1hcEFubm90YXRpb24oZGYgPSBjYW5jZXJfdHlwZSkKCmRhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCx2YXJzID0gYWxsX3RvcF9kZWcsc2xvdCA9ICJzY2FsZS5kYXRhIikgJT4lIHQoKQoKcHJpbnQoQ29tcGxleEhlYXRtYXA6OkhlYXRtYXAoZGF0YSxzaG93X2NvbHVtbl9uYW1lcyA9IEYscm93X25hbWVzX2dwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDcpLGNsdXN0ZXJfcm93cyA9IEYsICxuYW1lID0gIlotc2NvcmUgZXhwcmVzc2lvbiIsY2x1c3Rlcl9jb2x1bW5zID0gRix0b3BfYW5ub3RhdGlvbiA9IGNvbHVtbl9oYSkpCiAgCgpgYGAKCgoKCgoKCgojIyBDTlYgcGxvdCB7LnRhYnNldH0KYGBge3J9CiMgY3JlYXRlIGV4cHJlc3Npb24gbWF0cml4IG9mIGFjYyArIG5vcm1hbCBjZWxscyArIEhNU0Mgc2V1cmF0IGludGVncmF0ZWQKIyBhY2NfYWxsX2NlbGxzX25vQWNjMSA9IHN1YnNldChhY2NfYWxsX2NlbGxzLCBzdWJzZXQgPSBwYXRpZW50LmlkZW50ICE9ICJBQ0MxIikKIyBhY2NfZXhwciA9IGFjY19hbGxfY2VsbHNfbm9BY2MxQGFzc2F5cyRSTkFAZGF0YSAlPiUgYXMuZGF0YS5mcmFtZSgpCiMgaG1zY19leHByICA9IGFjYy5jb21iaW5lZEBhc3NheXMkaW50ZWdyYXRlZEBkYXRhICU+JSBhcy5kYXRhLmZyYW1lKCkKIyBhY2NfZXhwciA9IGFjY19leHByIFsgcm93bmFtZXMoaG1zY19leHByKSxdCiMgYWxsX2V4cHIgPSBjYmluZChhY2NfZXhwcixobXNjX2V4cHIpCiMgCiMgIyBjcmVhdGUgYW5ub3RhdGlvbiAKIyBhY2NfYW5ub3RhdGlvbl9pbnRlZ3JhdGVkICA9IGFzLmRhdGEuZnJhbWUoYWNjX2FsbF9jZWxsc0BtZXRhLmRhdGFbLCJjZWxsLnR5cGUiLGRyb3AgPSBGXSkKIyBhY2NfYW5ub3RhdGlvbl9pbnRlZ3JhdGVkID0gYWNjX2Fubm90YXRpb25faW50ZWdyYXRlZFtjb2xuYW1lcyhhbGxfZXhwciksLGRyb3AgPSBGXQojIGFjY19hbm5vdGF0aW9uX2ludGVncmF0ZWQgPSBhY2NfYW5ub3RhdGlvbl9pbnRlZ3JhdGVkICU+JSByb3duYW1lc190b19jb2x1bW4oIm9yaWcuaWRlbnQiKSAKCiMgI3dyaXRlIGV4cHJlc3Npb24gYW5kIGFubm90YXRpb24KIyB3cml0ZS50YWJsZShhY2NfYW5ub3RhdGlvbl9pbnRlZ3JhdGVkLCAiLi9EYXRhL2luZmVyQ05WL2FjY19hbm5vdGF0aW9uX2ludGVncmF0ZWQudHh0IiwgYXBwZW5kID0gRkFMU0UsIAojICAgICAgICAgICAgIHNlcCA9ICJcdCIsIGRlYyA9ICIuIixyb3cubmFtZXMgPSBGQUxTRSwgY29sLm5hbWVzID0gRikKIyAKIyAKIyB3cml0ZS50YWJsZShhbGxfZXhwciwgIi4vRGF0YS9pbmZlckNOVi9hbGwuNGljbnZfaW50ZWdyYXRlZC50eHQiLCBhcHBlbmQgPSBGQUxTRSwgCiMgICAgICAgICAgICAgc2VwID0gIlx0IiwgZGVjID0gIi4iLHJvdy5uYW1lcyA9IFQsIGNvbC5uYW1lcyA9IFQpCmBgYAoKYGBge3J9CnRyYWNlKGluZmVyY252OjpydW4sZWRpdCA9IFQpICMgdG8gc2tpcCBub3JtYWxpemF0aW9uLCBjaGFuZ2UgdG8gc2tpcF9wYXN0ID0gNCAoaHR0cHM6Ly9naXRodWIuY29tL2Jyb2FkaW5zdGl0dXRlL2luZmVyY252L2lzc3Vlcy8zNDYpCmBgYAoKYGBge3J9CgppbmZlcmNudl9vYmogPSBDcmVhdGVJbmZlcmNudk9iamVjdChyYXdfY291bnRzX21hdHJpeD0iLi9EYXRhL2luZmVyQ05WL2FsbC40aWNudl9pbnRlZ3JhdGVkLnR4dCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uc19maWxlPSIuL0RhdGEvaW5mZXJDTlYvYWNjX2Fubm90YXRpb25faW50ZWdyYXRlZC50eHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWxpbT0iXHQiLGdlbmVfb3JkZXJfZmlsZT0iLi9EYXRhL2luZmVyQ05WL2dlbmNvZGVfdjE5X2dlbmVfcG9zLnR4dCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLHJlZl9ncm91cF9uYW1lcz1jKCJDQUYiLCAiRW5kb3RoZWxpYWwiLCAiV0JDIikpICNncm91cHMgb2Ygbm9ybWFsIGNlbGxzCgppbmZlcmNudl9vYmpfZGVmYXVsdCA9IGluZmVyY252OjpydW4oaW5mZXJjbnZfb2JqLCBjdXRvZmY9MSwgb3V0X2Rpcj0nLi9EYXRhL2luZmVyQ05WL2luZmVyY252X2ludGVyZ3JhdGVkX291dHB1dCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2J5X2dyb3Vwcz1ULCBwbG90X3N0ZXBzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVub2lzZT1UUlVFLCBITU09RkFMU0UsIG5vX3ByZWxpbV9wbG90PVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbmdfcmVzPTMwMCkKdW50cmFjZShpbmZlcmNudjo6cnVuKQoKCmBgYAoKCmBgYHtyfQp0cmFjZShpbmZlcmNudjo6OmdldF9ncm91cF9jb2xvcl9wYWxldHRlICxlZGl0ID0gVCkgIyBjaGFuZ2UgIlNldDMiIHRvICJTZXQxIiBmb3IgbW9yZSBkaXN0aW5ndWlzaGFibGUgY29sb3JzCnBsb3RfY252KGluZmVyY252X29ial9kZWZhdWx0LCBvdXRwdXRfZm9ybWF0ID0gInBuZyIsICB3cml0ZV9leHByX21hdHJpeCA9IEZBTFNFLG91dF9kaXIgPSAiLi9EYXRhL2luZmVyQ05WL2luZmVyY252X2ludGVyZ3JhdGVkX291dHB1dCIscG5nX3Jlcwk9ODAwLG9ic190aXRsZSA9ICJNYWxpZ25hbnQgY2VsbHMiLHJlZl90aXRsZSA9ICJOb3JtYWwgY2VsbHMiLGNvbnRpZ19jZXggPSAyLCB0aXRsZSA9ICJDb3B5IG51bWJlciB2YXJpYXRpb24iKQp1bnRyYWNlKGluZmVyY252Ojo6Z2V0X2dyb3VwX2NvbG9yX3BhbGV0dGUpCmBgYAoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OCxyZXN1bHRzPSdhc2lzJ30KcHJpbnRfdGFiKHBsdCA9IGtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCIuL0RhdGEvaW5mZXJDTlYvaW5mZXJjbnZfaW50ZXJncmF0ZWRfb3V0cHV0L2luZmVyY252LnBuZyIpCiAgICAgICAgICAsdGl0bGUgPSAiQ05WIHBsb3QiLHN1YnRpdGxlX251bSA9IDMpCmBgYAoKCmBgYHtyLHJlc3VsdHM9J2FzaXMnfQpsaWJyYXJ5KGxpbW1hKQpzbW9vdGhlZD1hcHBseShpbmZlcmNudl9vYmpfZGVmYXVsdEBleHByLmRhdGEsMix0cmljdWJlTW92aW5nQXZlcmFnZSwgc3Bhbj0wLjAxKQpjbnNpZz1zcXJ0KGFwcGx5KChzbW9vdGhlZC0xKV4yLDIsbWVhbikpCgphY2NfYWxsX2NlbGxzIDwtIEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjY19hbGxfY2VsbHMsIG1ldGFkYXRhID0gY25zaWcsIGNvbC5uYW1lID0gImNvcHludW1iZXIiKQphY2NfYWxsX2NlbGxzID0gU2V0SWRlbnQob2JqZWN0ID0gYWNjX2FsbF9jZWxscyx2YWx1ZSA9ICJjZWxsLnR5cGUiKQoKcHJpbnRfdGFiKHBsdCA9IEZlYXR1cmVQbG90KGFjY19hbGxfY2VsbHMsICJjb3B5bnVtYmVyIixwdC5zaXplID0gMSxsYWJlbCA9IFQscmVwZWwgPSBUKSsKICAgICAgICAgICAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIndoaXRlIiwibGlnaHRibHVlIiwib3JhbmdlIiwicmVkIiwiZGFya3JlZCIpKQogICAgICAgICAgLHRpdGxlID0gIkNOViBVTUFQIixzdWJ0aXRsZV9udW0gPSAzKQoKYGBgCgoKCgojIEhNU0MgYW5hbHlzaXMgCiMjIFVNQVAgCmBgYHtyfQphY2MxX2NhbmNlcl9jZWxscyA9IEZpbmRDbHVzdGVycyhvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2ZXJib3NlID0gRixyZXNvbHV0aW9uID0gMC41KQpEaW1QbG90KG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHB0LnNpemUgPSAyKQpgYGAKCiMjIFNjb3JlcyAKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CkZlYXR1cmVQbG90KG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gYygiTVlCIiwiSkFHMSIpLHB0LnNpemUgPSAyKSsKRGltUGxvdChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxncm91cC5ieSAgPSBjKCJocHYzM19wb3NpdGl2ZSIpLHB0LnNpemUgPSAyKQoKYGBgCgojIyBERUcgey50YWJzZXR9CmBgYHtyIHJlc3VsdHM9J2FzaXMnfQpTZXRJZGVudChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YWx1ZSA9ICJzZXVyYXRfY2x1c3RlcnMiKQpkZWcgPSBGaW5kQWxsTWFya2VycyhvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMoYWNjMV9jYW5jZXJfY2VsbHMpLGRlbnNpZnkgPSBULHZlcmJvc2UgPSBGKQpmb3IgKGNsdXN0ZXIgaW4gdW5pcXVlKGRlZyRjbHVzdGVyKSkgewogIHByaW50X3RhYihwbHQgPSBkZWdbZGVnJGNsdXN0ZXIgPT0gY2x1c3RlcixdLHRpdGxlID0gIkRFRyIgLHN1YnRpdGxlX251bSA9IHRvY190YWJzX2xldmVsKQp9CmBgYAoKYGBge3IgcmVzdWx0cz0nYXNpcyd9CmZvciAoY2x1c3RlciBpbiB1bmlxdWUoZGVnJGNsdXN0ZXIpKSB7CiAgZGVnX29mX2NsdXN0ZXIgPSBkZWdbZGVnJGNsdXN0ZXIgPT0gY2x1c3RlcixdIAogICMgIHByaW50KGRlZ19vZl9jbHVzdGVyICVpbiUgb3JpZ2luYWxfbXlvX2dlbmVzICU+JSB3aGljaCgpKQogICMgcHJpbnQoZGVnX29mX2NsdXN0ZXIgJWluJSBvcmlnaW5hbF9sdW1fZ2VuZXMgJT4lIHdoaWNoKCkpCiAgcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICAgIGVucmljaG1lbnRfYW5hbHlzaXMoZGVnX29mX2NsdXN0ZXIsYmFja2dyb3VuZCA9VmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscyksZmRyX0N1dG9mZiA9IDAuMDEsaWRlbnQuMSA9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIkNsdXN0ZXIiLGNsdXN0ZXIpLGlkZW50LjIgPSAgcGFzdGUoIkNsdXN0ZXIiLGNsdXN0ZXIpLHNob3dfYnkgPSAxKQogICAgICAgICAgICAsdGl0bGUgPSBjbHVzdGVyLHN1YnRpdGxlX251bSA9IHRvY190YWJzX2xldmVsKQp9CgoKYGBgCgoKIyMgTk1GIHsudGFic2V0fQpgYGB7cHl0aG9ufQpmcm9tIGNubWYgaW1wb3J0IGNOTUYKaW1wb3J0IHBpY2tsZQpuZmVhdHVyZXMgPSAiMksiCmYgPSBvcGVuKCcuL0RhdGEvY05NRi9ITVNDX2NOTUZfaGFybW9ueV8yS3ZhcmdlbmVzL2NubWZfb2JqLnBja2wnLCAncmInKQpjbm1mX29iaiA9IHBpY2tsZS5sb2FkKGYpCmYuY2xvc2UoKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiLi9EYXRhL2NOTUYvSE1TQ19jTk1GX2hhcm1vbnlfMkt2YXJnZW5lcy9ITVNDX2NOTUZfaGFybW9ueV8yS3ZhcmdlbmVzLmtfc2VsZWN0aW9uLnBuZyIpCmBgYAoKYGBge3B5dGhvbn0Kc2VsZWN0ZWRfayA9IDMKZGVuc2l0eV90aHJlc2hvbGQgPSAwLjEKY25tZl9vYmouY29uc2Vuc3VzKGs9c2VsZWN0ZWRfaywgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQsc2hvd19jbHVzdGVyaW5nPVRydWUpCnVzYWdlX25vcm0sIGdlcF9zY29yZXMsIGdlcF90cG0sIHRvcGdlbmVzID0gY25tZl9vYmoubG9hZF9yZXN1bHRzKEs9c2VsZWN0ZWRfaywgZGVuc2l0eV90aHJlc2hvbGQ9ZGVuc2l0eV90aHJlc2hvbGQpCmBgYAoKYGBge3J9CmdlcF9zY29yZXMgPSBweSRnZXBfc2NvcmVzCmdlcF90cG0gPSBweSRnZXBfdHBtCmFsbF9tZXRhZ2VuZXM9IHB5JHVzYWdlX25vcm0KYGBgCgojIyBIYXJtb255IHJlc3VsdHMgey50YWJzZXR9CgoKCmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMCwgcmVzdWx0cz0nYXNpcyd9CiMgTWFrZSBtZXRhZ2VuZSBuYW1lcwpmb3IgKGkgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXMpKSB7CiAgY29sbmFtZXMoYWxsX21ldGFnZW5lcylbaV0gPSAibWV0YWdlbmUuIiAlPiUgcGFzdGUwKGkpCn0KCiNhZGQgZWFjaCBtZXRhZ2VuZSB0byBtZXRhZGF0YQpmb3IgKGkgaW4gMTpuY29sKGFsbF9tZXRhZ2VuZXMpKSB7CiAgbWV0YWdlX21ldGFkYXRhID0gYWxsX21ldGFnZW5lcyAlPiUgc2VsZWN0KGkpCiAgYWNjMV9jYW5jZXJfY2VsbHMgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxtZXRhZGF0YSA9IG1ldGFnZV9tZXRhZGF0YSkKfQpwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgIEZlYXR1cmVQbG90KG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gY29sbmFtZXMoYWxsX21ldGFnZW5lcyksY29tYmluZSA9IFQpLAogICAgICAgICAgdGl0bGUgPSAibWV0YWdlbmVzIGV4cHJlc3Npb24iLHN1YnRpdGxlX251bSA9IHRvY190YWJzX2xldmVsKQoKYGBgCgoKIyMgRW5yaWNobWVudCBhbmFseXNpcyBieSB0b3AgMjAwIGdlbmVzIG9mIGVhY2ggcHJvZ3JhbQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCByZXN1bHRzPSdoaWRlJ30KCmNhbm9uaWNhbF9wYXRod2F5cyA9IG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLCBjYXRlZ29yeSA9ICJDMiIpICU+JSBkcGx5cjo6ZmlsdGVyKGdzX3N1YmNhdCAhPSAiQ0dQIikgJT4lICBkcGx5cjo6ZGlzdGluY3QoZ3NfbmFtZSwgZ2VuZV9zeW1ib2wpCgpwbHRfbGlzdCA9IGxpc3QoKQpmb3IgKGkgaW4gMTpuY29sKGdlcF9zY29yZXMpKSB7CiAgdG9wX2dlbmVzID0gZ2VwX3Njb3JlcyAgJT4lICBhcnJhbmdlKGRlc2MoZ2VwX3Njb3Jlc1tpXSkpICNzb3J0IGJ5IHNjb3JlIGEKICB0b3AgPSBoZWFkKHJvd25hbWVzKHRvcF9nZW5lcyksMjAwKSAjdGFrZSB0b3AgdG9wX2dlbmVzX251bQogIHJlcyA9IGdlbmVzX3ZlY19lbnJpY2htZW50KGdlbmVzID0gdG9wLGJhY2tncm91bmQgPSByb3duYW1lcyhnZXBfc2NvcmVzKSxob21lciA9IFQsdGl0bGUgPSAKICAgICAgICAgICAgICAgICAgICBpLHNpbGVudCA9IFQscmV0dXJuX2FsbCA9IFQsY3VzdG9tX3BhdGh3YXlzID0gY2Fub25pY2FsX3BhdGh3YXlzKQogICAKICBwbHRfbGlzdFtbaV1dID0gcmVzJHBsdAp9CmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKGdyb2JzID0gcGx0X2xpc3QpCmBgYAoKYGBge3J9CmZvciAoaSBpbiAxOm5jb2woZ2VwX3Njb3JlcykpIHsKICByYW5rZWRfdmVjID0gZ2VwX3Njb3JlcyAlPiUgcHVsbChpKSAlPiUgIHNldE5hbWVzKHJvd25hbWVzKGdlcF9zY29yZXMpKQogIGh5cF9vYmogPC1oeXBlUl9mZ3NlYShzaWduYXR1cmUgPSByYW5rZWRfdmVjLGdlbmVzZXRzID0gZ2VuZXNldHMsdXBfb25seSA9IFQpCgogIHBsdCA9IGh5cF9kb3RzKGh5cF9vYmosbWVyZ2UgPSBGKSsgYWVzKHNpemU9YWJzKG5lcykpCiAgcHJpbnQocGx0KQp9CmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9MTB9CmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmFjYzFfY2FuY2VyX2NlbGxzID0gU2V0SWRlbnQob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFsdWUgPSAic2V1cmF0X2NsdXN0ZXJzIikKZm9yIChpIGluIDE6bmNvbChnZXBfc2NvcmVzKSkgewogIHRvcF9nZW5lcyA9IGdlcF9zY29yZXMgICU+JSAgYXJyYW5nZShkZXNjKGdlcF9zY29yZXNbaV0pKSAjc29ydCBieSBzY29yZSBhCiAgdG9wID0gaGVhZChyb3duYW1lcyh0b3BfZ2VuZXMpLDUwKSAjdGFrZSB0b3AgdG9wX2dlbmVzX251bQogIGRhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IHRvcCklPiUgc2NhbGUoKSAlPiUgdCgpIAogIG1ldGFnZW5lX2RhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpW2ldKQogIGNvbF9saXN0ID0gbGlzdChjaXJjbGl6ZTo6Y29sb3JSYW1wMihjKDAsIDEpLCBjKCJ3aGl0ZSIsICJyZWQiKSkpOyBuYW1lcyhjb2xfbGlzdCkgPSBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKVtpXQogIGNvbHVtbl9oYSA9IEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gbWV0YWdlbmVfZGF0YSxjb2wgPSBjb2xfbGlzdCkKICBwcmludChDb21wbGV4SGVhdG1hcDo6SGVhdG1hcChkYXRhLHNob3dfY29sdW1uX25hbWVzID0gRixyb3dfbmFtZXNfZ3AgPSBncmlkOjpncGFyKGZvbnRzaXplID0gNyksY2x1c3Rlcl9yb3dzID0gRiwgdG9wX2Fubm90YXRpb24gPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl9oYSxuYW1lID0gIlotc2NvcmUgZXhwcmVzc2lvbiIpKQogICAgCiAgcGRmKHBhc3RlMCgiLi9GaWd1cmVzL05NRl90b3BfZ2VuZXNfcHJvZ3JhbSIsaSwiLnBkZiIpKQogIHByaW50KENvbXBsZXhIZWF0bWFwOjpIZWF0bWFwKGRhdGEsc2hvd19jb2x1bW5fbmFtZXMgPSBGLHJvd19uYW1lc19ncCA9IGdyaWQ6OmdwYXIoZm9udHNpemUgPSA3KSxjbHVzdGVyX3Jvd3MgPSBGLCB0b3BfYW5ub3RhdGlvbiA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX2hhLG5hbWUgPSAiWi1zY29yZSBleHByZXNzaW9uIikpCiAgZGV2Lm9mZigpCn0KCmBgYAoKCgoKCgojIyBMdW0gTXlvIHNjb3JlCgpgYGB7cn0Kb3JpZ2luYWxfbXlvX2dlbmVzID0gYyggIlRQNjMiLCAiVFA3MyIsICJDQVYxIiwgIkNESDMiLCAiS1JUNSIsICJLUlQxNCIsICJBQ1RBMiIsICJUQUdMTiIsICJNWUxLIiwgIkRLSzMiKQpvcmlnaW5hbF9sdW1fZ2VuZXMgPSBjKCJLSVQiLCAiRUhGIiwgIkVMRjUiLCAiS1JUNyIsICJDTEROMyIsICJDTERONCIsICJDRDI0IiwgIkxHQUxTMyIsICJMQ04yIiwgIlNMUEkiICkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KRmVhdHVyZVBsb3QoYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBvcmlnaW5hbF9teW9fZ2VuZXMpCkZlYXR1cmVQbG90KGFjYzFfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gb3JpZ2luYWxfbHVtX2dlbmVzKQoKYGBgCgoKYGBge3J9CmFjY19jYW5jZXJDZWxsc19ub0FDQzEgPSBTZXRJZGVudChhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLHZhbHVlID0gInBhdGllbnQuaWRlbnQiKQpjYWxjdWxhdGVfc2NvcmUoZGF0YXNldCA9IGFjY19jYW5jZXJDZWxsc19ub0FDQzEsbXlvX2dlbmVzID0gb3JpZ2luYWxfbXlvX2dlbmVzLGx1bV9nZW5lcyA9IG9yaWdpbmFsX2x1bV9nZW5lcykKYGBgCgoKCiMjIE9yaWdpbmFsIHNjb3JlIG9mIEFDQzEKYGBge3J9CmNhbGN1bGF0ZV9zY29yZShkYXRhc2V0ID0gYWNjMV9jYW5jZXJfY2VsbHMsbXlvX2dlbmVzID0gb3JpZ2luYWxfbXlvX2dlbmVzLGx1bV9nZW5lcyA9IG9yaWdpbmFsX2x1bV9nZW5lcyxsdW1fdGhyZXNob2xkID0gMCxteW9fdGhyZXNob2xkID0gMCkKYGBgCgpgYGB7cn0KZGF0YSA9IEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gYyhvcmlnaW5hbF9sdW1fZ2VuZXMpKQphID0gY29yKGRhdGEpCkNvbXBsZXhIZWF0bWFwOjpIZWF0bWFwKG1hdHJpeCA9IGNvcihkYXRhKSxuYW1lID0gInBlYXJzb24iKQpgYGAKCgojIyMgTXlvIGdlbmVzCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBjb2xsYXBzZT1UfQpteW9fcHJvdGVpbl9tYXJrZXJzID0gYygiQ05OMSIsICJUUDYzIiwiQUNUQTIiKQp0b3BfbXlvICA9IHRvcF9jb3JyZWxhdGVkKGRhdGFzZXQgPSBhY2MxX2NhbmNlcl9jZWxscywgZ2VuZXMgPSBteW9fcHJvdGVpbl9tYXJrZXJzLHRocmVzaG9sZCA9IDAuMzUpCnByaW50KCJOdW1iZXIgb2YgZ2VuZXMgPSAiICU+JSBwYXN0ZShsZW5ndGgodG9wX215bykpKQptZXNzYWdlKCJOYW1lcyBvZiBnZW5lczoiKQp0b3BfbXlvICU+JSBoZWFkKDMwKQptZXNzYWdlKCJHZW5lcyB0aGF0IGFsc28gYXBlYXJlZCBpbiB0aGUgb3JpZ2luYWwgc2NvcmU6IikKYmFzZTo6aW50ZXJzZWN0KHRvcF9teW8sb3JpZ2luYWxfbXlvX2dlbmVzKSAKYGBgCgoKCmBgYHtyfQpteW9fZW5yaWNoX3JlcyA9IGdlbmVzX3ZlY19lbnJpY2htZW50KGdlbmVzID0gdG9wX215byxiYWNrZ3JvdW5kID0gcm93bmFtZXMoYWNjMV9jYW5jZXJfY2VsbHMpLGhvbWVyID0gVCx0aXRsZSA9ICJteW8gdG9wIGVucmljaG1lbnQiLGN1c3RvbV9wYXRod2F5cyA9IGx1bWluYWxfZ3MpCm15b19lbnJpY2hfcmVzCmBgYAojIyMgTHVtIGdlbmVzCmBgYHtyfQpsdW1fcHJvdGVpbl9tYXJrZXJzID0gYygiS0lUIikKdG9wX2x1bSAgPSB0b3BfY29ycmVsYXRlZChkYXRhc2V0ID0gYWNjMV9jYW5jZXJfY2VsbHMsIGdlbmVzID0gbHVtX3Byb3RlaW5fbWFya2Vycyx0aHJlc2hvbGQgPSAwLjMwLG5fdmFyZ2VuZXMgPSA1MDAwKQpwcmludCgiTnVtYmVyIG9mIGdlbmVzID0gIiAlPiUgcGFzdGUobGVuZ3RoKHRvcF9sdW0pKSkKbWVzc2FnZSgiTmFtZXMgb2YgZ2VuZXM6IikKdG9wX2x1bSAlPiUgaGVhZCgzMCkKbWVzc2FnZSgiR2VuZXMgdGhhdCBhbHNvIGFwZWFyZWQgaW4gdGhlIG9yaWdpbmFsIHNjb3JlOiIpCmJhc2U6OmludGVyc2VjdCh0b3BfbHVtLG9yaWdpbmFsX2x1bV9nZW5lcykgCmBgYAoKYGBge3J9Cmx1bV9lbnJpY2hfcmVzID0gZ2VuZXNfdmVjX2VucmljaG1lbnQoZ2VuZXMgPSB0b3BfbHVtLGJhY2tncm91bmQgPSByb3duYW1lcyhhY2MxX2NhbmNlcl9jZWxscyksaG9tZXIgPSBULHRpdGxlID0gImx1bSB0b3AgZW5yaWNobWVudCIsY3VzdG9tX3BhdGh3YXlzID0gbHVtaW5hbF9ncykKbHVtX2VucmljaF9yZXMKYGBgCgpgYGB7cn0Kcm93bmFtZXMobXlvX2VucmljaF9yZXMpID0gbXlvX2VucmljaF9yZXMkcGF0aHdheV9uYW1lCm15b19lbnJpY2hlZF9nZW5lcyA9IG15b19lbnJpY2hfcmVzWzEsImdlbmVJRCJdICU+JSBzdHJzcGxpdChzcGxpdCA9ICIvIikgJT4lIC5bWzFdXSAlPiUgYyguLG15b19wcm90ZWluX21hcmtlcnMpICNhZGQgb3JpZ2luYWwgbWFya2VycwpteW9zY29yZT1GZXRjaERhdGEob2JqZWN0ID1hY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gIG15b19lbnJpY2hlZF9nZW5lcyxzbG90ID0gImRhdGEiKSAlPiUgcm93TWVhbnMoKQphY2MxX2NhbmNlcl9jZWxscz1BZGRNZXRhRGF0YShhY2MxX2NhbmNlcl9jZWxscyxteW9zY29yZSwibXlvX3Njb3JlIikKCgpteW9zY29yZT1GZXRjaERhdGEob2JqZWN0ID1hY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gIHRvcF9teW8sc2xvdCA9ICJkYXRhIikgJT4lIHJvd01lYW5zKCkKYWNjMV9jYW5jZXJfY2VsbHM9QWRkTWV0YURhdGEoYWNjMV9jYW5jZXJfY2VsbHMsbXlvc2NvcmUsIm15b19zY29yZSIpCmBgYAoKCiMjIEhQVgojIyMgSFBWIFVNQVAKCmBgYHtyfQpIUFYzM19QMyA9IGZyZWFkKCIuL0RhdGEvSFBWMzNfUDMudHh0Iixjb2wubmFtZXMgPSBjKCJwbGF0ZSIsInJlYWRzIikpICU+JSBhcy5kYXRhLmZyYW1lKCkKSFBWMzNfUDMuZGYgPSBIUFYzM19QMyAlPiUgbXV0YXRlKAogIHBsYXRlID0gZ3N1Yih4ID1IUFYzM19QMyRwbGF0ZSwgcmVwbGFjZW1lbnQgPSAiIixwYXR0ZXJuID0gIl8uKiQiKSAKICAlPiUgZ3N1YihwYXR0ZXJuID0gIi1QIixyZXBsYWNlbWVudCA9ICIuUCIpIAogICU+JSBnc3ViKHBhdHRlcm4gPSAiLSIscmVwbGFjZW1lbnQgPSAiXyIsKQogICkKSFBWMzNfUDMuZGYgPSBIUFYzM19QMy5kZiAlPiUgZHBseXI6OmZpbHRlcihIUFYzM19QMy5kZiRwbGF0ZSAlaW4lIGNvbG5hbWVzKGFjYzFfY2FuY2VyX2NlbGxzKSkKcm93bmFtZXMoSFBWMzNfUDMuZGYpICA8LSBIUFYzM19QMy5kZiRwbGF0ZQpIUFYzM19QMy5kZiRwbGF0ZSA9IE5VTEwKCgpIUFYzM19QMiA9IGZyZWFkKCIuL0RhdGEvSFBWMzNfUDIudHh0Iixjb2wubmFtZXMgPSBjKCJwbGF0ZSIsInJlYWRzIikpICU+JSBhcy5kYXRhLmZyYW1lKCkKSFBWMzNfUDIuZGYgPSBIUFYzM19QMiAlPiUgbXV0YXRlKAogIHBsYXRlID0gZ3N1Yih4ID1IUFYzM19QMiRwbGF0ZSwgcmVwbGFjZW1lbnQgPSAiIixwYXR0ZXJuID0gIl8uKiQiKSAKICAlPiUgZ3N1YihwYXR0ZXJuID0gInBsYXRlMi0iLHJlcGxhY2VtZW50ID0gInBsYXRlMl8iLCkKICAlPiUgZ3N1YihwYXR0ZXJuID0gIi0iLHJlcGxhY2VtZW50ID0gIlxcLiIsKQogICkKSFBWMzNfUDIuZGYgPSBIUFYzM19QMi5kZiAlPiUgZHBseXI6OmZpbHRlcihIUFYzM19QMi5kZiRwbGF0ZSAlaW4lIGNvbG5hbWVzKGFjYzFfY2FuY2VyX2NlbGxzKSkKcm93bmFtZXMoSFBWMzNfUDIuZGYpICA8LSBIUFYzM19QMi5kZiRwbGF0ZQpIUFYzM19QMi5kZiRwbGF0ZSA9IE5VTEwKCkhQVjMzID0gcmJpbmQoSFBWMzNfUDMuZGYsSFBWMzNfUDIuZGYpCmFjYzFfY2FuY2VyX2NlbGxzID0gQWRkTWV0YURhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsbWV0YWRhdGEgPSBIUFYzMyxjb2wubmFtZSA9ICJIUFYzMy5yZWFkcyIpCkZlYXR1cmVQbG90KGFjYzFfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gIkhQVjMzLnJlYWRzIixtYXguY3V0b2ZmID0gMTApCmBgYAoKCmBgYHtyfQoKZGF0YSA9IEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gIkhQVjMzLnJlYWRzIikKCmRhdGEgPSBkYXRhICU+JSBtdXRhdGUoIjAgcmVhZHMiID0gaWZfZWxzZShjb25kaXRpb24gPSBIUFYzMy5yZWFkcyA9PSAwLHRydWUgPSAxLGZhbHNlID0gMCkpCmRhdGEgPSBkYXRhICU+JSBtdXRhdGUoIjEgcmVhZHMiID0gaWZfZWxzZShjb25kaXRpb24gPSBIUFYzMy5yZWFkcyA9PSAxLHRydWUgPSAxLGZhbHNlID0gMCkpCmRhdGEgPSBkYXRhICU+JSBtdXRhdGUoIjIgcmVhZHMiID0gaWZfZWxzZShjb25kaXRpb24gPSBIUFYzMy5yZWFkcyA9PSAyLHRydWUgPSAxLGZhbHNlID0gMCkpCmRhdGEgPSBkYXRhICU+JSBtdXRhdGUoIjMtMjMgcmVhZHMiID0gaWZfZWxzZShjb25kaXRpb24gPSBIUFYzMy5yZWFkcyA+PTMgJkhQVjMzLnJlYWRzICA8MjQsdHJ1ZSA9IDEsZmFsc2UgPSAwKSkKZGF0YSA9IGRhdGEgJT4lIG11dGF0ZSgiMjQrIHJlYWRzIiA9IGlmX2Vsc2UoY29uZGl0aW9uID0gSFBWMzMucmVhZHMgPj0yNCx0cnVlID0gMSxmYWxzZSA9IDApKQpkYXRhID0gY29sU3VtcyhkYXRhWywyOm5jb2woZGF0YSldKSAlPiUgYXMuZGF0YS5mcmFtZSgpCm5hbWVzKGRhdGEpWzFdID0gImNvdW50IgpkYXRhID0gcm93bmFtZXNfdG9fY29sdW1uKGRhdGEsdmFyID0gImJpbiIpCmRhdGEKZ2dwbG90KGRhdGE9ZGF0YSwgYWVzKHg9ZmFjdG9yKGJpbixsZXZlbHMgPSBjKCIwIHJlYWRzIiwiMSByZWFkcyIsIjIgcmVhZHMiLCIzLTIzIHJlYWRzIiwiMjQrIHJlYWRzIikpLCB5PWNvdW50KSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgZmlsbD0ic3RlZWxibHVlIikgKyB4bGFiKCJIUFYgUmVhZHMiKSsgdGhlbWVfbWluaW1hbCgpKwogIGdlb21fdGV4dChhZXMobGFiZWw9Y291bnQpLCB2anVzdD0tMC41LCBjb2xvcj0iYmxhY2siLCBzaXplPTMuNSkKYGBgCgoKYGBge3J9CmhwdjMzX3Bvc2l0aXZlID0gSFBWMzMgJT4lIGRwbHlyOjptdXRhdGUoaHB2MzNfcG9zaXRpdmUgPSBjYXNlX3doZW4ocmVhZHMgPj0gMTAgfiAicG9zaXRpdmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlYWRzIDwgMTAgfiAibmVnYXRpdmUiKQopCgoKCmhwdjMzX3Bvc2l0aXZlJHJlYWRzID0gTlVMTAphY2MxX2NhbmNlcl9jZWxscyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLG1ldGFkYXRhID0gaHB2MzNfcG9zaXRpdmUpCmBgYAoKYGBge3J9CkRpbVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsZ3JvdXAuYnkgID0gYygiaHB2MzNfcG9zaXRpdmUiKSxwdC5zaXplID0gMikKRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSAiTVlCIikKCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KGJpb21hUnQpCmVuc2VtYmwgPSB1c2VFbnNlbWJsKGJpb21hcnQ9ImVuc2VtYmwiLCBkYXRhc2V0PSJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiKQpgYGAKCiMjIyBERUcgaW50ZWdyYXRlZCB3aWxjb3ggCmBgYHtyfQojIGFjYzFfY2FuY2VyX2NlbGxzW1siUk5BLlRQTSJdXSA9IENyZWF0ZUFzc2F5T2JqZWN0KGNvdW50cyA9ICgyKiphY2MxX2NhbmNlcl9jZWxsc0Bhc3NheXMkUk5BQGNvdW50cyktMSkKIyBhY2MxX2NhbmNlcl9jZWxscyA9IEZpbmRWYXJpYWJsZUZlYXR1cmVzKGFjYzFfY2FuY2VyX2NlbGxzLG5mZWF0dXJlcyA9IDI1MDAwLGFzc2F5ID0gIlJOQS5UUE0iKQojIGFjYzFfY2FuY2VyX2NlbGxzID0gRmluZFZhcmlhYmxlRmVhdHVyZXMoYWNjMV9jYW5jZXJfY2VsbHMsbmZlYXR1cmVzID0gMjUwMDAsYXNzYXkgPSAiUk5BIikKYWNjMV9jYW5jZXJfY2VsbHMgPSBGaW5kVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscyxuZmVhdHVyZXMgPSAyMDAwMCxhc3NheSA9ICJpbnRlZ3JhdGVkIikKCmFjYzFfY2FuY2VyX2NlbGxzID0gU2V0SWRlbnQoYWNjMV9jYW5jZXJfY2VsbHMsIHZhbHVlID0iaHB2MzNfcG9zaXRpdmUiKQpgYGAKCmBgYHtyIGZpZy53aWR0aD04LCBlY2hvPVRSVUUscmVzdWx0cz0naGlkZScsZmlnLmtlZXA9J2FsbCd9CgojIGxpYnJhcnkoImJpb21hUnQiKQojIG1hcnQgPC0gdXNlTWFydChiaW9tYXJ0PSJlbnNlbWJsIiwgZGF0YXNldD0iaHNhcGllbnNfZ2VuZV9lbnNlbWJsIikKIyBhbGxfY29kaW5nX2dlbmVzIDwtIGdldEJNKGF0dHJpYnV0ZXMgPSBjKCAiaGduY19zeW1ib2wiKSwgZmlsdGVycyA9IGMoImJpb3R5cGUiKSwgdmFsdWVzID0gbGlzdChiaW90eXBlPSJwcm90ZWluX2NvZGluZyIpLCBtYXJ0ID0gbWFydCkKIyAgICAKCmZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscyxhc3NheSA9ICJSTkEiKSAKYWNjX2RlZyA8LSBGaW5kTWFya2VycyhhY2MxX2NhbmNlcl9jZWxscywgaWRlbnQuMSA9ICJwb3NpdGl2ZSIsaWRlbnQuMiA9ICJuZWdhdGl2ZSIsZmVhdHVyZXMgPSBmZWF0dXJlcyxkZW5zaWZ5ID0gVCxsb2dmYy50aHJlc2hvbGQgPSAwLjI1LG1pbi5wY3QgPSAwLjE1LCAgICBtZWFuLmZ4biA9IGZ1bmN0aW9uKHgpIHsKICAgICAgcmV0dXJuKGxvZyhyb3dNZWFucyh4KSArIDEsIGJhc2UgPSAyKSkgIyBjaGFuZ2UgZnVuYyB0byBjYWxjdWxhdGUgbG9nRkMgaW4gbG9nIHNwYWNlIGRhdGEgKGRlZmF1bHQgdG8gZXhwb25lbnQgZGF0YSkKICAgIH0pCgojIGVucmljaG1lbnRfYW5hbHlzaXMoYWNjX2RlZyxiYWNrZ3JvdW5kID0gVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscyksZmRyX0N1dG9mZiA9IDAuMDEsaWRlbnQuMSA9ICJITVNDIixpZGVudC4yID0gIkFDQyIsc2hvd19ieSA9IDEpCmFjY19kZWckZmRyPC1wLmFkanVzdChwID0gYXMudmVjdG9yKGFjY19kZWckcF92YWwpICxtZXRob2QgPSAiZmRyIikKIyBhY2NfZGVnW2MoIk1ZQiIsIkpBRzEiKSxdCiMgYWNjX2RlZyAlPiUgaGVhZCgpCiMgZ2VuZWRlc2MgPC0gZ2V0Qk0oYXR0cmlidXRlcz1jKCdleHRlcm5hbF9nZW5lX25hbWUnLCdkZXNjcmlwdGlvbicpLCBmaWx0ZXJzID0gJ2V4dGVybmFsX2dlbmVfbmFtZScsIHZhbHVlcyA9IGFjY19kZWcgJT4lIHJvd25hbWVzKCksIG1hcnQgPWVuc2VtYmwpICAKIyAKIyBhbGxfdXBfZ2VuZXMgPSBtZXJnZShhY2NfZGVnLGdlbmVkZXNjLGJ5Lng9InJvdy5uYW1lcyIsYnkueSA9ICJleHRlcm5hbF9nZW5lX25hbWUiLGFsbC54ID0gVCxzb3J0ID1GKQojIGFsbF91cF9nZW5lcwojIGdlbmVzID0gYWxsX3VwX2dlbmVzICU+JSBkcGx5cjo6ZmlsdGVyKFJvdy5uYW1lcyAlaW4lIGMoIk1ZQiIsIkpBRzEiKSkgJT4lIGRwbHlyOjpmaWx0ZXIocF92YWw8MC4wNSkKIyBnZW5lcwpgYGAKCmBgYHtyfQphY2NfZGVnCmFjY19kZWdbYygiTVlCIiwiSkFHMSIpLF0KCmBgYAoKIyMjIERFRyBMUiBsYXRlbnQgdmFycyBwbGF0ZQoKYGBge3J9CmxpYnJhcnkoImJpb21hUnQiKQojIG1hcnQgPC0gdXNlTWFydChiaW9tYXJ0PSJlbnNlbWJsIiwgZGF0YXNldD0iaHNhcGllbnNfZ2VuZV9lbnNlbWJsIikKIyBhbGxfY29kaW5nX2dlbmVzIDwtIGdldEJNKGF0dHJpYnV0ZXMgPSBjKCAiaGduY19zeW1ib2wiKSwgZmlsdGVycyA9IGMoImJpb3R5cGUiKSwgdmFsdWVzID0gbGlzdChiaW90eXBlPSJwcm90ZWluX2NvZGluZyIpLCBtYXJ0ID0gbWFydCkKCmZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscykKZmVhdHVyZXMgPSBhY2MxX2NhbmNlcl9jZWxsc0Bhc3NheXMkUk5BQGRhdGEgJT4lIHJvd01lYW5zKCkgJT4lIHNvcnQoZGVjcmVhc2luZyA9IFQpICU+JSBoZWFkKDMwMDApICU+JSBuYW1lcygpCmZlYXR1cmVzICA9IGludGVyc2VjdChmZWF0dXJlcywgVmFyaWFibGVGZWF0dXJlcyhhY2MxX2NhbmNlcl9jZWxscykgKQojIGZlYXR1cmVzICA9IGludGVyc2VjdChmZWF0dXJlcywgYWxsX2NvZGluZ19nZW5lc1ssMV0gKQoKYWNjX2RlZyA8LQogIEZpbmRNYXJrZXJzKAogICAgYWNjMV9jYW5jZXJfY2VsbHMsCiAgICBpZGVudC4xID0gInBvc2l0aXZlIiwKICAgIGlkZW50LjIgPSAibmVnYXRpdmUiLAogICAgZmVhdHVyZXMgPSBmZWF0dXJlcywKICAgIGRlbnNpZnkgPSBULAogICAgYXNzYXkgPSAiUk5BIiwKICAgIHRlc3QudXNlID0gIkxSIiwKICAgIGxhdGVudC52YXJzID0gInBsYXRlIiwKICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMSwKICAgIG1pbi5wY3QgPSAwLjEsCiAgICBvbmx5LnBvcyA9IEYsCiAgICBtZWFuLmZ4biA9IGZ1bmN0aW9uKHgpIHsKICAgICAgcmV0dXJuKGxvZyhyb3dNZWFucyh4KSArIDEsIGJhc2UgPSAyKSkgIyBjaGFuZ2UgZnVuYyB0byBjYWxjdWxhdGUgbG9nRkMgaW4gbG9nIHNwYWNlIGRhdGEgKGRlZmF1bHQgdG8gZXhwb25lbnQgZGF0YSkKICAgICAgIyByZXR1cm4obG9nKHJvd01lYW5zKGV4cG0xKHgpKSArIDEsIGJhc2UgPSAyKSkKCiAgICB9CiAgKQphY2NfZGVnJGZkcjwtcC5hZGp1c3QocCA9IGFzLnZlY3RvcihhY2NfZGVnJHBfdmFsKSAsbWV0aG9kID0gImZkciIgKQoKYGBgCgoKYGBge3J9CnJhbmtlZF92ZWMgPSBhY2NfZGVnWywiYXZnX2xvZzJGQyJdJT4lIHNldE5hbWVzKHJvd25hbWVzKGFjY19kZWcpKSAlPiUgbmEub21pdCgpICMgbWFrZSBuYW1lZCB2ZWN0b3IKCmh5cF9vYmogPC1oeXBlUl9mZ3NlYShzaWduYXR1cmUgPSByYW5rZWRfdmVjLGdlbmVzZXRzID0gZ2VuZXNldHMsdXBfb25seSA9IEYpCmh5cF9kb3RzKGh5cF9vYmosbWVyZ2UgPSBGKdeWCgoKYGBgCgpgYGB7cn0KYWNjX2RlZwphY2NfZGVnW2MoIk1ZQiIsIkpBRzEiKSxdCgpgYGAKCnZvbGNhbm8gcGxvdCBsb2cyKG1lYW4gbG9nVFBNIEhQVispIC0gbG9nMihtZWFuIGxvZ1RQTSBIUFYtKQpgYGB7cn0Kdm9sY2Fub19wbG90KGRlX2dlbmVzID0gYWNjX2RlZyxmY19jdXRvZmYgPSAxLjMsIGZkcl9jdXRvZmYgPSAwLjEsc2hvd19nZW5lX25hbWVzID0gYygiTVlCIiwiSkFHMSIpLGlkZW50MSA9ICJIUFYzMyBwb3NpdGl2ZSIsaWRlbnQyID0gIkhQVjMzIG5lZ2F0aXZlIix0b3BfZ2VuZXNfdGV4dCA9IDUpCgphY2NfZGVnMiA9IGFjY19kZWcgJT4lIG11dGF0ZShhdmdfbG9nMkZDID0gZXhwKGF2Z19sb2cyRkMpKQp2b2xjYW5vX3Bsb3QoZGVfZ2VuZXMgPSBhY2NfZGVnMixmY19jdXRvZmYgPSAyKiooMS4zKSwgZmRyX2N1dG9mZiA9IDAuMSxzaG93X2dlbmVfbmFtZXMgPSBjKCJNWUIiLCJKQUcxIiksaWRlbnQxID0gIkhQVjMzIHBvc2l0aXZlIixpZGVudDIgPSAiSFBWMzMgbmVnYXRpdmUiLHRvcF9nZW5lc190ZXh0ID0gNSkKYGBgCgp2b2xjYW5vIHBsb3QgbG9nMihtZWFuIGxvZ1RQTSBIUFYrKSAtIGxvZzIobWVhbiBsb2dUUE0gSFBWLSkKCmBgYHtyfQoKYWNjX2RlZyA8LQogIEZpbmRNYXJrZXJzKAogICAgYWNjMV9jYW5jZXJfY2VsbHMsCiAgICBpZGVudC4xID0gInBvc2l0aXZlIiwKICAgIGlkZW50LjIgPSAibmVnYXRpdmUiLAogICAgZmVhdHVyZXMgPSBmZWF0dXJlcywKICAgIGRlbnNpZnkgPSBULAogICAgYXNzYXkgPSAiUk5BIiwKICAgIHRlc3QudXNlID0gIkxSIiwKICAgIGxhdGVudC52YXJzID0gInBsYXRlIiwKICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMzUsCiAgICBtaW4ucGN0ID0gMC4xLAogICAgbWVhbi5meG4gPSBmdW5jdGlvbih4KSB7CiAgICAgIHJldHVybihyb3dNZWFucyh4KSArIDEpICMgY2hhbmdlIGZ1bmMgdG8gY2FsY3VsYXRlIGxvZ0ZDIGluIGxvZyBzcGFjZSBkYXRhIChkZWZhdWx0IHRvIGV4cG9uZW50IGRhdGEpCiAgICB9CiAgKQphY2NfZGVnJGZkcjwtcC5hZGp1c3QocCA9IGFzLnZlY3RvcihhY2NfZGVnJHBfdmFsKSAsbWV0aG9kID0gImZkciIgKQpgYGAKCmBgYHtyfQphY2NfZGVnW2MoIk1ZQiIsIkpBRzEiKSxdCmBgYAoKCnZvbGNhbm8gcGxvdCAobWVhbiBsb2dUUE0gSFBWKykgLSAobWVhbiBsb2dUUE0gSFBWLSkKCmBgYHtyfQp2b2xjYW5vX3Bsb3QoZGVfZ2VuZXMgPSBhY2NfZGVnLGZjX2N1dG9mZiA9IDEuMywgZmRyX2N1dG9mZiA9IDAuMSxzaG93X2dlbmVfbmFtZXMgPSBjKCJNWUIiLCJKQUcxIiksaWRlbnQxID0gIkhQVjMzIHBvc2l0aXZlIixpZGVudDIgPSAiSFBWMzMgbmVnYXRpdmUiLHRvcF9nZW5lc190ZXh0ID0gNSkreGxhYigiYXZnIGRpZmYiKQpgYGAKCiMjIyBIUFYgdnMgZ2VuZXMKYGBge3IgZmlnLndpZHRoPTh9CmdlbmVzID0gYygiQUs0IiwgIkFOTE4iLCAiQ0FQRyIsICJJRlQxMjIiLCAiSkFHMSIsICJNWUIiLCAiUEJSTTEiICkKbXliX3ZzX2hwdiA9IEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gYygiaHB2MzNfcG9zaXRpdmUiLGdlbmVzKSkKZGYgPSByZXNoYXBlMjo6bWVsdChteWJfdnNfaHB2LHZhbHVlLm5hbWUgPSAibG9nVFBNIikgJT4lIGRwbHlyOjpyZW5hbWUoZ2VuZSA9IHZhcmlhYmxlKQoKCnN0YXQudGVzdCA8LSBkZiAlPiUKICAgIGdyb3VwX2J5KGdlbmUpICU+JQogIHdpbGNveF90ZXN0KGxvZ1RQTSB+IGhwdjMzX3Bvc2l0aXZlKSAlPiUKICBtdXRhdGUoeS5wb3NpdGlvbiA9IDUpCgpzdGF0LnRlc3QKCnN0YXQudGVzdCA8LSBzdGF0LnRlc3QgJT4lIAogIGFkZF94eV9wb3NpdGlvbih4ID0gImdlbmUiLCBkb2RnZSA9IDAuOCkKCmdnYm94cGxvdCgKICBkZiwKICB4ID0gImdlbmUiLAogIHkgPSAibG9nVFBNIiwKICBjb2xvciA9ICJocHYzM19wb3NpdGl2ZSIsCiAgcGFsZXR0ZSA9ICJqY28iLAogIGFkZCA9ICJqaXR0ZXIiCikrIHN0YXRfcHZhbHVlX21hbnVhbChzdGF0LnRlc3QseS5wb3NpdGlvbiA9IDEzLCBsYWJlbCA9ICJwID0ge3B9IixyZW1vdmUuYnJhY2tldCA9IFQpCmBgYAoKYGBge3J9Cm5vdGNoX2dlbmVzID0gYygiSkFHMSIsIkpBRzIiLCJOT1RDSDMiLCJOT1RDSDIiLCJOT1RDSDEiLCJETEwxIiwiTVlCIiwiSEVTNCIsIkhFWTEiLCJIRVkyIiwiTlJBUlAiKQpmb3IgKGdlbmUgIGluIG5vdGNoX2dlbmVzKSB7CiAgbXliX3ZzX2hwdiA9IEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gYygiaHB2MzNfcG9zaXRpdmUiLGdlbmUpKSAKICBteWJfdnNfaHB2JGhwdjMzX3Bvc2l0aXZlID0gcGFzdGUoIkhQVjMzIixteWJfdnNfaHB2JGhwdjMzX3Bvc2l0aXYpCgogIHAgPSBnZ2JveHBsb3QobXliX3ZzX2hwdiwgeCA9ICJocHYzM19wb3NpdGl2ZSIsIHkgPSBnZW5lLAogICAgICAgICAgICBwYWxldHRlID0gImpjbyIsCiAgICAgICAgICAgIGFkZCA9ICJqaXR0ZXIiKSsgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsY29tcGFyaXNvbnMgPSBsaXN0KGMoIkhQVjMzIHBvc2l0aXZlIiwiSFBWMzMgbmVnYXRpdmUiKSkpKyBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBmdW5jdGlvbih4KSBkYXRhLmZyYW1lKHk9bWF4KHgpKjEuMiwgbGFiZWwgPSBwYXN0ZSgiTWVhbj0iLHJvdW5kKG1lYW4oeCksZGlnaXRzID0gMikpKSwgZ2VvbT0idGV4dCIpICt5bGFiKCJsb2cyKGdlbmUpIikrZ2d0aXRsZShnZW5lKQogIHByaW50X3RhYihwLHRpdGxlID0gZ2VuZSkKfQoKYGBgCgoKYGBge3J9Cm5vdGNoX3RhcmdldHMgPSBjKCJOT1RDSDMiLCJIRVM0IiwiSEVZMSIsIkhFWTIiLCJOUkFSUCIpIApub3RjaF9saWdhbmQgPSBjKCJKQUcxIiwiSkFHMiIsIkRMTDEiKQpub3RjaF9nZW5lcyA9IGxpc3Qobm90Y2hfdGFyZ2V0cyA9IG5vdGNoX3RhcmdldHMsbm90Y2hfbGlnYW5kID0gbm90Y2hfbGlnYW5kKQpmb3IgKGkgIGluIDE6bGVuZ3RoKG5vdGNoX2dlbmVzKSkgewogIGdlbmVzID0gbm90Y2hfZ2VuZXNbW2ldXQogIG5hbWUgPSBuYW1lcyggbm90Y2hfZ2VuZXMpW2ldCiAgbXliX3ZzX2hwdiA9IEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gYyhnZW5lcykpICU+JSByb3dNZWFucygpCiAgbXliX3ZzX2hwdiA9IG15Yl92c19ocHYgJT4lIGNiaW5kKEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gYygiaHB2MzNfcG9zaXRpdmUiKSkpCiAgY29sbmFtZXMobXliX3ZzX2hwdilbMV0gPSAiZ2VuZV9zZXQiCiAgbXliX3ZzX2hwdiRocHYzM19wb3NpdGl2ZSA9IHBhc3RlKCJIUFYzMyIsbXliX3ZzX2hwdiRocHYzM19wb3NpdGl2KQoKICBwID0gZ2dib3hwbG90KG15Yl92c19ocHYsIHggPSAiaHB2MzNfcG9zaXRpdmUiLCB5ID0gImdlbmVfc2V0IiwKICAgICAgICAgICAgcGFsZXR0ZSA9ICJqY28iLAogICAgICAgICAgICBhZGQgPSAiaml0dGVyIikrIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAid2lsY294LnRlc3QiLGNvbXBhcmlzb25zID0gbGlzdChjKCJIUFYzMyBwb3NpdGl2ZSIsIkhQVjMzIG5lZ2F0aXZlIikpKSsgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gZnVuY3Rpb24oeCkgZGF0YS5mcmFtZSh5PW1heCh4KSoxLjIsIGxhYmVsID0gcGFzdGUoIk1lYW49Iixyb3VuZChtZWFuKHgpLGRpZ2l0cyA9IDIpKSksIGdlb209InRleHQiKSAreWxhYigibG9nMihnZW5lKSIpK2dndGl0bGUobmFtZSkKIHByaW50KHApCn0KCmBgYAoKYGBge3J9CiAgY29yX2RhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoIk1ZQiIsIm15b19zY29yZSIpKQpnZ3Bsb3QoY29yX2RhdGEsIGFlcyh4PU1ZQiwgeT1teW9fc2NvcmUpKSArIAogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iKSsKICAgIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgICsKICBnZW9tX3BvaW50KCkKCgogIGNvcl9kYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBjKCJKQUcxIiwibXlvX3Njb3JlIikpCmdncGxvdChjb3JfZGF0YSwgYWVzKHg9SkFHMSwgeT1teW9fc2NvcmUpKSArIAogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iKSsKICAgIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgICsKICBnZW9tX3BvaW50KCkKCiAgY29yX2RhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoIkpBRzIiLCJteW9fc2NvcmUiKSkKZ2dwbG90KGNvcl9kYXRhLCBhZXMoeD1KQUcyLCB5PW15b19zY29yZSkpICsgCiAgICBzdGF0X2NvcihtZXRob2QgPSAicGVhcnNvbiIpKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSAgKwogIGdlb21fcG9pbnQoKQoKICBjb3JfZGF0YSA9IEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gYygiRExMMSIsIm15b19zY29yZSIpKQpnZ3Bsb3QoY29yX2RhdGEsIGFlcyh4PURMTDEsIHk9bXlvX3Njb3JlKSkgKyAKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIikrCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pICArCiAgZ2VvbV9wb2ludCgpCgoKICBjb3JfZGF0YSA9IEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gbm90Y2hfdGFyZ2V0cykgJT4lIHJvd01lYW5zKCkKICBjb3JfZGF0YSA9IGNvcl9kYXRhICU+JSBjYmluZChGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoIm15b19zY29yZSIpKSkKICBjb2xuYW1lcyhjb3JfZGF0YSlbMV0gPSAibm90Y2hfdGFyZ2V0cyIKCiAgZ2dwbG90KGNvcl9kYXRhLCBhZXMoeD1ub3RjaF90YXJnZXRzLCB5PW15b19zY29yZSkpICsgCiAgICBzdGF0X2NvcihtZXRob2QgPSAicGVhcnNvbiIpKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSAgKwogIGdlb21fcG9pbnQoKQogIAogIAogICAgY29yX2RhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IG5vdGNoX2xpZ2FuZCkgJT4lIHJvd01lYW5zKCkKICBjb3JfZGF0YSA9IGNvcl9kYXRhICU+JSBjYmluZChGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoIm15b19zY29yZSIpKSkKICBjb2xuYW1lcyhjb3JfZGF0YSlbMV0gPSAibm90Y2hfbGlnYW5kIgoKICBnZ3Bsb3QoY29yX2RhdGEsIGFlcyh4PW5vdGNoX2xpZ2FuZCwgeT1teW9fc2NvcmUpKSArIAogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iKSsKICAgIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgICsKICBnZW9tX3BvaW50KCkKICAKYGBgCgoKYGBge3J9Cm5vdGNoX3Njb3JlID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFsbF9hY2NfY2FuY2VyX2NlbGxzLHZhcnMgPSBub3RjaF90YXJnZXRzKSAlPiUgcm93TWVhbnMoKQphbGxfYWNjX2NhbmNlcl9jZWxscyAgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhbGxfYWNjX2NhbmNlcl9jZWxscyxtZXRhZGF0YSA9IG5vdGNoX3Njb3JlLGNvbC5uYW1lID0gIm5vdGNoX3Njb3JlIikKRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWxsX2FjY19jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSAibm90Y2hfc2NvcmUiICkKYGBgCgoKYGBge3J9Cm15b19tYXJrZXJzID0gYygiVFA2MyIsICJUUDczIiwgIktSVDE0IiwgIkNESDMiKQpzY29yZSA9IEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gbXlvX21hcmtlcnMpICU+JSByb3dNZWFucygpCmFjYzFfY2FuY2VyX2NlbGxzICA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLG1ldGFkYXRhID0gc2NvcmUsY29sLm5hbWUgPSAibXlvX21hcmtlcnNfc2NvcmUiKQpGZWF0dXJlUGxvdChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9ICJteW9fbWFya2Vyc19zY29yZSIscHQuc2l6ZSA9IDIgKQoKCm1hcmtlcnMgPSBjKCJDTEROMyIsICJBTlhBOCIsICJFSEYiLCAiS0lUIikKc2NvcmUgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IG1hcmtlcnMpICU+JSByb3dNZWFucygpCmFjYzFfY2FuY2VyX2NlbGxzICA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLG1ldGFkYXRhID0gc2NvcmUsY29sLm5hbWUgPSAibHVtX21hcmtlcnNfc2NvcmUiKQpGZWF0dXJlUGxvdChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9ICJsdW1fbWFya2Vyc19zY29yZSIgLHB0LnNpemUgPSAyICkKYGBgCgoKPHNjcmlwdCBzcmM9Imh0dHBzOi8vaHlwb3RoZXMuaXMvZW1iZWQuanMiIGFzeW5jPjwvc2NyaXB0Pgo=